سؤال

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

لأغراض التوضيح ، قمت بإنشاء مثال بسيط للغاية.

قل النموذج الخاص بي يحتوي على هذه الكائنات.

public class Person
{
    public string Name {get; set;}
    public PhoneNumber PhoneNumber {get; set;}
}

public class PhoneNumber
{
    public string AreaCode {get; set;}
    public string LocalNumber {get; set;}
}

ولدي المجلدات التالية لكل من هذه النماذج. لا يحتاج الشخص الذي يحتاج إلى ملء الفونومورات ولكنه لا يريد تكرار الكود في رابط الفون. كيف يمكن أن تعود إلى توجيه الموثق النجابي؟

public class PersonBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext     bindingContext)
    {
        Person person = new Person();
        person.Name = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "Name")).AttemptedValue

        // This is where I'd like to have the PhoneNumber object use binding from another customer ModelBinder.
        // Of course the bindingContext.ModelName should be updated to its current value + "PhoneNumber"
        person.PhoneNumber = ???;  // I don't want to explicitly call the PhoneNumberBinder it should go through standard Binding routing.  (ie.  ModelBinders.Binders[typeof(PhoneNumber)] = new PhoneNumberBinder();)

        return person;       
    }
}

public class PhoneNumberBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext     bindingContext)
    {
        PhoneNumber phoneNumber = new PhoneNumber();
        phoneNumber.AreaCode = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "AreaCode")).AttemptedValue
        phoneNumber.LocalNumber = bindingContext.ValueProvider.GetValue(String.Format("{0}.{1}", bindingContext.ModelName, "LocalNumber")).AttemptedValue

        return phoneNumber;
    }
}

وبالطبع ، قمت بتسجيل طرازاتي في ملف global.asax.cs.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterRoutes(RouteTable.Routes);

    ModelBinders.Binders[typeof(Person)] = new PersonBinder();
    ModelBinders.Binders[typeof(PhoneNumber)] = new PhoneNumberBinder();
}

شكرًا،

جوستين

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

المحلول

حسنًا ، تمكنت من التوصل إلى حل. لا تتردد في التعليق على صلاحيتها.

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
     Person person = new Person();
     person.Name = bindingContext.ValueProvider.GetValue("Name").AttemptedValue

     if (bindingContext.ModelName == String.Empty)
     {
         bindingContext.ModelName = "PhoneNumber";
     }
     else
     {
         bindingContext.ModelName = bindingContext.ModelName + ".PhoneNumber";
     }

     PhoneNumber phoneNumber = new PhoneNumber();
     bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => phoneNumber, phoneNumber.GetType());

     IModelBinder binder = ModelBinders.Binders[typeof(PhoneNumber)];
     if (binder == null)
     {
          binder = ModelBinders.Binders.DefaultBinder;
     }

     person.PhoneNumber = binder.BindModel(controllerContext, bindingContext) as PhoneNumber;

     return person;                         
}

إليك ملخص لما قمت به.

  1. ابحث عن نموذج الطراز باستخدام مجموعة ModelBinders.binders التي يمكن الوصول إليها عالميًا (متوقفة إلى الافتراضي إذا لم يتم تسجيل المرء)
  2. قم بإنشاء ModelMetAdataprovider للنموذج الذي أربطه.
  3. قم بتعيين خاصية اسم النموذج الخاصة بـ BindingContext على خاصية النموذج التي أحاول أن تملأها ("Phonenumber").

نصائح أخرى

بدلاً من كتابة موثق ، يمكنك استخدام السيارات والتعامل مع بناء النموذج المعقد في الإجراء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top