سؤال

أحاول تنفيذ عقد خدمة يحتوي على طريقة تأخذ واجهة عامة ، ويتم إعطاء هذه الواجهة العامة نفسها معلمة واجهة.لقد قمت بتزيين واجهة الخدمة بـ ServiceKnownType ، وقمت بتزيين تنفيذ الخدمة بـ KnownType العادي ، وقمت بتزيين تنفيذ عقد البيانات بـ KnownType العادي:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallbacks))]
[ServiceKnownType(typeof(Batch<object>))]
[ServiceKnownType(typeof(Command))]
public interface IActions
{
    [OperationContract]
    IResponse TakeAction(IBatch<ICommand> commands);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
[KnownType(typeof(Batch<object>))]
[KnownType(typeof(Command))]
internal class Actions : IActions
{
}

[DataContract]
[KnownType(typeof(Command))]
public class Batch<T> : IBatch<T>
{
}

بالنسبة للسجل ، لدي Batch لأنه يبدو أنه يمكنك فقط التعبير عن نوع معروف لنوع عام مرة واحدة - يبدو أنه يصدر BatchOfanyType ، لكنني لست متأكدًا من كيفية التعامل مع هذا.

الاستثناء الذي أحصل عليه هو "إضافة أي أنواع غير معروفة بشكل ثابت إلى قائمة الأنواع المعروفة - على سبيل المثال ، باستخدام السمة KnownTypeAttribute أو عن طريق إضافتها إلى قائمة الأنواع المعروفة التي تم تمريرها إلى DataContractSerializer."

هل هناك أي شيء واضح أنني أفعله خطأ؟هل الواجهات العامة للواجهات غير مدعومة؟للسجل أنا على C # 2.0 و .NET 3.0 لهذا المشروع.

هل كانت مفيدة؟

المحلول

يمكنك استخدام الواجهات في تعريفات عقد الخدمة إذا كنت تريد ذلك حقًا ، طالما أنك تقوم بتضمين الأنواع المعروفة كما تفعل (مع تعديل بسيط ، انظر أدناه).

على ما يبدو ، فإن استخدام واجهة كمعامل نوع عام يجعلها جسرًا بعيدًا جدًا عن C # 3.0.لقد غيرت سمة النوع المعروف إلى

[ServiceKnownType(typeof(Batch<Command>))]
public interface IActions
{
}

مما يجعلها تعمل ، إلى حد ما.سيعمل التسلسل وإلغاء التسلسل بحد ذاته ، ولكنك تواجه هذا الاستثناء بعد ذلك:

تعذر تحويل كائن من النوع 'Batch`1 [Command]' \ n لكتابة 'IBatch`1 [ICommand]'.

لكي يعمل هذا المصبوب ، تحتاج إلى دعم اللغة للتغاير العام للنوع ، وهو شيء تم تقديمه في C # 4.0.لكي تعمل في C # 4.0 ، ستحتاج إلى إضافة معدل التباين:

public interface IBatch<out T>
{
}

ثم يعمل بشكل مثالي ... للأسف أنت لا تستخدم C # 4.0.

شيء واحد أخير حول استخدام الواجهات في عقد الخدمة الخاص بك: إذا كنت تقوم بإنشاء مرجع خدمة منها ، فسيتم كتابة جميع معلمات الواجهة كـ object ، لأن نوع الواجهة الأصلي ليس جزءًا من البيانات الوصفية.يمكنك مشاركة العقود من خلال مرجع تجميع ، أو إعادة بناء الوكيل الذي تم إنشاؤه يدويًا لإصلاحه ، ولكن بشكل عام ، قد يكون استخدام واجهات مع WCF مشكلة أكثر مما يستحق.

نصائح أخرى

WCF هو نظام قائم على رسائل SOA - يمكنه إرسال أي شيء عبر السلك بتنسيق XML المتسلسل الذي يمكن التعبير عنه في مخطط XML.

لسوء الحظ ، لا يعرف مخطط XML أي شيء لا الواجهات ولا العوامل العامة ، لذلك لا - لا يمكنك إجراء تسلسل عام لهذه - تحتاج إلى استخدام أنواع محددة.

لا يمكنك إجراء تسلسل للواجهة.الواجهة تحدد العقد فقط ، وليس الكائن.أعتقد أن الاستثناء الوحيد لهذا هو واجهة ISerializable.

يمكن إجراء تسلسل لعلم الوراثة ، ولكن مع بعض القيود.على سبيل المثال ، بالنظر إلى عقد البيانات:

[DataContract]
public class Foo<T>
{
     [DataMember]
     public T Value { get; set; }
}

وعقد الخدمة:

[ServiceContract]
public interface IService1
{
     [OperationContract]
     Foo<String> GetData();
}

وتنفيذ الخدمة:

public class Service1 : IService1
{
   public Foo<string> GetData()
   {
       return new Foo<string>() { Value = "My test string" };
   }
}

بعد تعيين مرجع الخدمة للخدمة المذكورة أعلاه ، يمكن تشغيل هذا الرمز:

ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();

ServiceReference1.FooOfstring temp = client.GetData();

MessageBox.Show(temp.Value);

ويتم عرض مربع الرسالة مع "سلسلة الاختبار الخاصة بي".

لاحظ أن الخدمة نفسها ليست عامة ، ولكن عقد البيانات المستخدم هو.علاوة على ذلك ، فإن عقد البيانات الذي تم إنشاؤه من جانب العميل ليس عامًا ، ولكنه فئة "مسطحة" لها قيمة خاصية من نوع السلسلة:

[System.Runtime.Serialization.DataMemberAttribute()]
public string Value 
{ 
   get {...} 
   set {...} 
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top