سؤال

من هذا السؤال, يبدو أنه من المنطقي أن يكون هناك تحكم إنشاء ViewModel أن يعكس بصورة أكثر دقة النموذج الذي عرض هو محاولة لعرض ولكن أنا غريبة عن بعض الاتفاقيات (أنا جديدة على نمط MVC, اذا لم يكن بالفعل واضح).

في الأساس كان لدي الأسئلة التالية:

  1. أنا عادة أحب أن يكون فئة واحدة/الملف.فهل يعقل هذا مع ViewModel إذا كان فقط يتم إنشاؤه على يد البيانات من وحدة تحكم الرأي ؟
  2. إذا ViewModel لا تنتمي في الملفات الخاصة بها و أنت باستخدام دليل/هيكل المشروع للحفاظ على الأشياء منفصلة ، أين ViewModel الملف تنتمي ؟ في تحكم الدليل ؟

هذا في الأساس هو عليه الآن.ربما لدي بعض الأسئلة القادمة, ولكن هذا لم يزعجني منذ ساعة الماضية أو نحو ذلك ، و لا يمكن أن يبدو للعثور على ثابت التوجيه في مكان آخر.

تحرير: تبحث في العينة NerdDinner التطبيق على CodePlex يبدو أن ViewModels هي جزء من تحكم, لكنه لا يزال يجعلني غير مريح أنهم ليسوا في الملفات الخاصة بهم.

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

المحلول

لقد خلق ما أسميه "ViewModel" لكل عرض.أنا وضعت لهم في مجلد يسمى ViewModels في MVC مشروع ويب.لا اسم لهم بعد تحكم العمل (أو عرض) التي يمثلونها.حتى إذا كنت بحاجة إلى تمرير البيانات إلى الاشتراك عرض على عضوية المراقب أنا خلق MembershipSignUpViewModel.cs الطبقة ووضعها في ViewModels مجلد.

ثم إضافة الخصائص الضرورية و الطرق لتسهيل نقل البيانات من وحدة تحكم العرض.يمكنني استخدام Automapper على من ViewModel إلى نموذج المجال والعودة مرة أخرى إذا لزم الأمر.

هذا يعمل أيضا بشكل جيد مركب ViewModels التي تحتوي على الخصائص التي هي من نوع آخر ViewModels.فعلى سبيل المثال إذا كان لديك 5 الحاجيات على صفحة الفهرس في عضوية تحكم و أنت خلقت ViewModel لكل إطلالة جزئية - كيف يمكنك تمرير البيانات من مؤشر العمل إلى جزئيات?قمت بإضافة خاصية MembershipIndexViewModel من نوع MyPartialViewModel و عند التقديم الجزئي سوف تمر في نموذج.MyPartialViewModel.

القيام بهذه الطريقة يسمح لك لضبط جزئية ViewModel خصائص دون الحاجة إلى تغيير مؤشر عرض على الإطلاق.فإنه لا يزال فقط يمر في نموذج.MyPartialViewModel حتى لا يكون هناك أقل من فرصة أنه سيكون لديك للذهاب من خلال سلسلة كاملة من جزئيات لإصلاح شيء ما عندما كل ما تفعله هو إضافة خاصية الجزئي ViewModel.

كما سيتم إضافة مساحة الاسم "MyProject.ويب.ViewModels" على شبكة الإنترنت.التكوين حتى يتسنى لي الرجوع إليها في أي عرض دون أي إضافة صريح استيراد البيان على كل عرض.فقط يجعل من قليلا أكثر نظافة.

نصائح أخرى

فصل الطبقات حسب الفئة (تحكم, ViewModels, فلاتر إلخ.) هو هراء.

إذا كنت تريد كتابة كود من أجل الوطن القسم من موقع الويب الخاص بك (/) ثم إنشاء مجلد باسم البيت و وضع هناك HomeController, IndexViewModel, AboutViewModel ، إلخ.وما يتصل بها من جميع الطبقات المستخدمة من قبل المنزل الإجراءات.

إذا كان لديك المشتركة فصول ، مثل ApplicationController ، يمكنك وضعه في جذر المشروع الخاص بك.

لماذا منفصلة الأشياء التي هي ذات الصلة (HomeController, IndexViewModel) والحفاظ على الأشياء معا أن لا علاقة على الإطلاق (HomeController, AccountController) ?


كتبت بلوق وظيفة عن هذا الموضوع.

أحافظ على تطبيق الطبقات في مجلد فرعي يسمى "الأساسية" (أو منفصلة مكتبة فئة) و تستخدم نفس أساليب مثل KIGG عينة التطبيق ولكن مع بعض التغييرات الطفيفة لجعل بلدي تطبيقات أكثر الجافة.

لقد خلق BaseViewData الطبقة /Core/ViewData/ أين يمكنني تخزين مشتركة الموقع خصائص واسعة.

بعد هذا أنا أيضا إنشاء كل من وجهة نظري ViewData الطبقات في نفس المجلد ثم تستمد من BaseViewData و عرض خصائص محددة.

ثم إنشاء ApplicationController أن تحكم تنبع من.على ApplicationController عام GetViewData الأسلوب على النحو التالي:

protected T GetViewData<T>() where T : BaseViewData, new()
    {
        var viewData = new T
        {
           Property1 = "value1",
           Property2 = this.Method() // in the ApplicationController
        };
        return viewData;
    }

أخيرا في وحدة تحكم عمل أقوم به التالية لبناء نموذج ViewData

public ActionResult Index(int? id)
    {
        var viewData = this.GetViewData<PageViewData>();
        viewData.Page = this.DataContext.getPage(id); // ApplicationController
        ViewData.Model = viewData;
        return View();
    }

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

أ ViewModel الدرجة هل هناك لتغليف أجزاء متعددة من البيانات ممثلة في حالات دروس في واحدة سهلة لإدارة كائن التي يمكن أن تمر إلى طريقة العرض الخاصة بك.

فمن المنطقي أن يكون لديك ViewModel دروس في الملفات الخاصة بهم في الدليل نفسه.في مشاريع بلدي لدي مجلد فرعي من مجلد نماذج يسمى ViewModels.حيث ان ViewModels (مثلا ، ProductViewModel.cs) الحية.

لا يوجد مكان جيد للحفاظ على النماذج الخاصة بك في.يمكنك الاحتفاظ بها منفصلة في الجمعية إذا كان المشروع كبير و هناك الكثير من ViewModels (نقل البيانات الكائنات).أيضا يمكنك الاحتفاظ بها في مجلد منفصل من موقع المشروع.على سبيل المثال ، Oxite يتم وضعها في Oxite المشروع الذي يحتوي على الكثير من مختلف الطبقات أيضا.تحكم في Oxite انتقلت إلى مشروع منفصل و الآراء في مشروع منفصل أيضا.
في CodeCampServer ViewModels تسمية *شكل يتم وضعها في واجهة المستخدم المشروع في نماذج مجلد.
في MvcPress المشروع يتم وضعها في بيانات المشروع الذي يحتوي أيضا على كل رمز للعمل مع قاعدة البيانات وأكثر من ذلك قليلا (ولكن أنا لا أوصي هذا النهج ، إنها مجرد عينة)
لذلك يمكنك أن ترى أن هناك العديد من وجهة نظر.وعادة ما تبقي لي ViewModels (DTO الكائنات) في موقع المشروع.ولكن عندما يكون لدي أكثر من 10 نماذج يفضل نقلها لفصل الجمعية.عادة في هذه الحالة أنا تتحرك وحدات تحكم منفصلة الجمعية أيضا.
سؤال آخر هو كيف يمكن بسهولة خريطة جميع البيانات من النموذج الخاص بك ViewModel.أقترح أن يكون لديك نظرة AutoMapper المكتبة.أنا أحب ذلك كثيرا جدا ، يفعل كل العمل القذر بالنسبة لي.
و أنا أيضا أقترح أن ننظر إلى SharpArchitecture المشروع.فإنه يوفر جيد جدا هندسة المشاريع و أنه يحتوي على الكثير من بارد أطر guidances و المجتمع الكبير.

وهنا مقتطف من أفضل الممارسات:

    public class UserController : Controller
    {
        private readonly IUserService userService;
        private readonly IBuilder<User, UserCreateInput> createBuilder;
        private readonly IBuilder<User, UserEditInput> editBuilder;

        public UserController(IUserService userService, IBuilder<User, UserCreateInput> createBuilder, IBuilder<User, UserEditInput> editBuilder)
        {
            this.userService = userService;
            this.editBuilder = editBuilder;
            this.createBuilder = createBuilder;
        }

        public ActionResult Index(int? page)
        {
            return View(userService.GetPage(page ?? 1, 5));
        }

        public ActionResult Create()
        {
            return View(createBuilder.BuildInput(new User()));
        }

        [HttpPost]
        public ActionResult Create(UserCreateInput input)
        {
            if (input.Roles == null) ModelState.AddModelError("roles", "selectati macar un rol");

            if (!ModelState.IsValid)
                return View(createBuilder.RebuildInput(input));

            userService.Create(createBuilder.BuilEntity(input));
            return RedirectToAction("Index");
        }

        public ActionResult Edit(long id)
        {
            return View(editBuilder.BuildInput(userService.GetFull(id)));
        }

        [HttpPost]
        public ActionResult Edit(UserEditInput input)
        {           
            if (!ModelState.IsValid)
                return View(editBuilder.RebuildInput(input));

            userService.Save(editBuilder.BuilEntity(input));
            return RedirectToAction("Index");
        }
}

نحن رمي كل من ViewModels في مجلد نماذج (كل منطق الأعمال في فصل ServiceLayer المشروع)

شخصيا أقترح إذا ViewModel هو أي شيء ولكن تافهة ثم استخدام فئة منفصلة.

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

في حالتنا لدينا نماذج جنبا إلى جنب مع وحدات تحكم في مشروع منفصل عن وجهات النظر.

وكقاعدة عامة من الإبهام, حاولنا التحرك وتجنب معظم ViewData["..."] الأشياء ViewModel وبالتالي علينا تجنب الصب والسحر سلاسل, وهو أمر جيد.

ViewModel وكذلك يحمل بعض خصائص مشتركة مثل ترقيم الصفحات معلومات عن قوائم أو معلومات رأس الصفحة إلى رسم فتات الخبز و الألقاب.في هذه اللحظة قاعدة الطبقة يحمل الكثير من المعلومات في رأيي و قد تقسيمه إلى ثلاثة قطع, أبسط و المعلومات اللازمة 99% من الصفحات على قاعدة نموذج عرض ثم نموذج قوائم نموذجا من النماذج التي تحمل بيانات خاصة أن سيناريوهات ترث من قاعدة واحدة.

أخيرا, نحن نقوم بتطبيق نموذج عرض لكل كيان للتعامل مع معلومات محددة.

التعليمات البرمجية في وحدة تحكم:

    [HttpGet]
        public ActionResult EntryEdit(int? entryId)
        {
            ViewData["BodyClass"] = "page-entryEdit";
            EntryEditViewModel viewMode = new EntryEditViewModel(entryId);
            return View(viewMode);
        }

    [HttpPost]
    public ActionResult EntryEdit(Entry entry)
    {
        ViewData["BodyClass"] = "page-entryEdit";            

        #region save

        if (ModelState.IsValid)
        {
            if (EntryManager.Update(entry) == 1)
            {
                return RedirectToAction("EntryEditSuccess", "Dictionary");
            }
            else
            {
                return RedirectToAction("EntryEditFailed", "Dictionary");
            }
        }
        else
        {
            EntryEditViewModel viewModel = new EntryEditViewModel(entry);
            return View(viewModel);
        }

        #endregion
    }

التعليمات البرمجية في نموذج عرض:

public class EntryEditViewModel
    {
        #region Private Variables for Properties

        private Entry _entry = new Entry();
        private StatusList _statusList = new StatusList();        

        #endregion

        #region Public Properties

        public Entry Entry
        {
            get { return _entry; }
            set { _entry = value; }
        }

        public StatusList StatusList
        {
            get { return _statusList; }
        }

        #endregion

        #region constructor(s)

        /// <summary>
        /// for Get action
        /// </summary>
        /// <param name="entryId"></param>
        public EntryEditViewModel(int? entryId)
        {
            this.Entry = EntryManager.GetDetail(entryId.Value);                 
        }

        /// <summary>
        /// for Post action
        /// </summary>
        /// <param name="entry"></param>
        public EntryEditViewModel(Entry entry)
        {
            this.Entry = entry;
        }

        #endregion       
    }

المشاريع:

  • DevJet.شبكة الإنترنت ( ASP.NET MVC ويب المشروع)

  • DevJet.ويب.التطبيق.قاموس ( a فصل الدرجة مشروع المكتبة)

    في هذا المشروع, أنا جعلت بعض المجلدات مثل:الدال ، BLL ، بو ، VM (مجلد عرض نماذج)

إنشاء طريقة عرض نموذج قاعدة الطبقة التي عادة الخصائص المطلوبة مثل نتيجة العملية السياقية البيانات ، يمكنك أيضا وضع المستخدم الحالي البيانات و الأدوار

class ViewModelBase 
{
  public bool HasError {get;set;} 
  public string ErrorMessage {get;set;}
  public List<string> UserRoles{get;set;}
}

في قاعدة تحكم الدرجة طريقة مثل PopulateViewModelBase() هذا الأسلوب سوف تملأ البيانات السياقية و أدوار المستخدمين.على HasError و رسالة الخطأ تعيين هذه الخصائص إذا كان هناك استثناء في حين سحب البيانات من خدمة/db.ربط هذه الخصائص على العرض لإظهار خطأ.أدوار المستخدمين يمكن استخدامها لإظهار إخفاء القسم على عرض تستند إلى الأدوار.

لملء عرض نماذج مختلفة على الإجراءات يمكن أن تكون متسقة من خلال وجود قاعدة تحكم مع مجردة طريقة FillModel

class BaseController :BaseController 
{
   public PopulateViewModelBase(ViewModelBase model) 
{
   //fill up common data. 
}
abstract ViewModelBase FillModel();
}

في وحدات تحكم

class MyController :Controller 
{

 public ActionResult Index() 
{
   return View(FillModel()); 
}

ViewModelBase FillModel() 
{ 
    ViewModelBase  model=;
    string currentAction = HttpContext.Current.Request.RequestContext.RouteData.Values["action"].ToString(); 
 try 
{ 
   switch(currentAction) 
{  
   case "Index": 
   model= GetCustomerData(); 
   break;
   // fill model logic for other actions 
}
}
catch(Exception ex) 
{
   model.HasError=true;
   model.ErrorMessage=ex.Message;
}
//fill common properties 
base.PopulateViewModelBase(model);
return model;
}
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top