سؤال

الآن رأيت بعض الأسئلة مثل هذا، لكنها ليست بالضبط ما أريد أن أسأله، لذلك بالنسبة لجميع تلك التي يصرخ مكررة، أعتذر :).

أنا بالكاد لمست ASP.NET MVC ولكن من ما أفهمه لا يوجد أي عرض / سيطرات ... غرامة. لذلك سؤالي هو ما هو البديل للإبقاء على حالة السيطرة؟ هل نعود إلى المدرسة القديمة ASP حيث قد نحاكي ما يفعله ASP.NET ViewState / ControlState من خلال إنشاء مدخلات نموذج مخفي مع حالة عنصر التحكم، أو مع MVC، فهل نتحمل AJAX دائما والاحتفاظ بجميع جانب عميل الدولة وجعل AJAX مكالمات للتحديث؟

هذا السؤال لديه بعض الإجابات، الحفاظ على العارض في ASP.NET MVC؟, ، ليس بالضبط ما أبحث عنه في إجابة.

تحديث: شكرا لجميع الإجابات حتى الآن. فقط لمسح ما لا أبحث عنه وما أبحث عنه:

لا تبحث عن:

  • حل الجلسة
  • حل كوكي
  • لا تتطلع إلى Mimic WebForms في MVC

ما أنا / كان يبحث عنه:

  • الطريقة التي تحتفظ بها فقط الحالة في إعادة النشر إذا لم تنتعش البيانات إلى عنصر تحكم. أعتقد أن WebForms مع السيناريو الخاص بربط الشبكة فقط على تحميل الصفحة الأولية، أي فقط إعادة تسمية البيانات عند الضرورة فقط. كما ذكرت، أنا لا أحاول تحاكي أجهزة الإنترنت، فقط أتساءل ما هي آليات MVC عروض.
هل كانت مفيدة؟

المحلول

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

[AcceptVerbs(HttpVerbs.Get)]   
public ActionResult CreatePost()
{
  return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(FormCollection formCollection)
{
  try
  {
    // do your logic here

    // maybe u want to stop and return the form
    return View(formCollection);
  }
  catch 
  {
    // this will pass the collection back to the ViewEngine
    return View(formCollection);
  }
}

ما يحدث التالي هو أن المشؤون يأخذ النظافة القائمة في القائمة على المفاتيح داخل المجموعة باستخدام أسماء المعرف / القيم لديك في رأيك، باستخدام HTML Helpers. علي سبيل المثال:

<div id="content">

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: <%= Html.TextBox("Title", Model["Title"], 50) %><br />
  Enter the Post Body: <%= Html.TextArea("Body", Model["Body"]) %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

لاحظ أن TextBox و Textarea لديه معرفات العنوان والجسم؟ الآن، لاحظ كيف يمكنني إعداد القيم من كائن نموذج العرض؟ نظرا لأنك مرت في صيغة نموذج (ويجب أن تضع الرأي ليتم كتابتها بقوة مع نموذج عمل)، يمكنك الآن الوصول إليه. أو، دون كتابة قوية، يمكنك ببساطة استخدام ViewData ["العنوان"] (على ما أعتقد).

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

الآن، الرمز أعلاه هو في أبسط أشكاله أو هوستها باستخدام FormCollection. تصبح الأمور مثيرة للاهتمام عند البدء في استخدام ViewModels، بدلا من FormCollection. يمكنك البدء في إضافة التحقق من الصحة الخاصة بك لنماذجك / ViewModels ولديك وحدة التحكم فقاعة أخطاء التحقق من صحة مخصصة تلقائيا. هذه إجابة ليوم آخر رغم ذلك.

أود أن أقترح استخدام PostFormViewModel بدلا من كائن ما بعد ذلك، ولكن لكل منها. في كلتا الحالتين، من خلال مطالبة كائن في طريقة العمل، يمكنك الآن الحصول على طريقة ISVALD () يمكنك الاتصال بها.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(Post post)
{

  // errors should already be in the collection here
  if (false == ModelState.IsValid())
    return View(post);

  try
  {
    // do your logic here

    // maybe u want to stop and return the form
    return View(post);
  }
  catch 
  {
    // this will pass the collection back to the ViewEngine
    return View(post);
  }
}

وستحتاج وجهة نظرك المكتوبة بقوة إلى تعديل:

<div id="content">

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: <%= Html.TextBox("Title", Model.Title, 50) %><br />
  Enter the Post Body: <%= Html.TextArea("Body", Model.Body) %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

يمكنك أن تأخذها خطوة أخرى وعرض الأخطاء أيضا في العرض، مباشرة من ModelState التي قمت بتعيينها في وحدة التحكم.

<div id="content">

  <%= Html.ValidationSummary() %>

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: 
    <%= Html.TextBox("Title", Model.Title, 50) %>
    <%= Html.ValidationMessage("Title") %><br />

  Enter the Post Body: 
    <%= Html.TextArea("Body", Model.Body) %>
    <%= Html.ValidationMessage("Body") %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

ما هو مثير للاهتمام مع هذا النهج هو أنك سوف تلاحظ أنني لا أعدد ملخص التحقق من الصحة، ولا رسائل التحقق من الصحة الفردية في العرض. أحب ممارسة مفاهيم DDD، مما يعني التحكم في رسائل التحقق من صحة (وملخصات) في نطاقي وانتقلت في شكل مجموعة. ثم، أقوم بحلقة تحصيله (إذا كانت هناك أخطاء موجودة) وإضافتها إلى مجموعة ModelState.Adderors الحالية. الباقي هو تلقائي عند إعادة عرض (المشاركة).

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

وفي هذا الأمر، يغطي أول المكسرات الخام والبراغي في إطار MVC بأكمله. يغطي الأخير التقنيات المتقدمة خارج Relm الرسمية ل Microsoft، مع العديد من الأدوات الخارجية لجعل حياتك أسهل بكثير (Castle Windsor، موك، إلخ).

نصائح أخرى

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

لا أستطيع أن أوصي كتاب ستيفن ساندرسون برو ASP.NET MVC بالبربريس بما يكفي للوصول إلى هذا النمط وهذا التنفيذ لذلك.

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

في ASP.NET MVC، إذا اتبعت النموذج، فلن تحتاج إلى الحفاظ على حالة عناصر النموذج. تتوفر قيم عنصر النموذج عند النشر حيث يمكن لمراقب التحكم عنها (التحقق من صحة وتحديثات قاعدة البيانات، إلخ). بالنسبة لأي عناصر شكل يتم عرضها بمجرد معالجة المنشور، فإنك (المطور) مسؤولا عن تهيئة لهم - لا يفعل الإطار تلقائيا لك.

ومع ذلك، قرأت عن آلية تسمى Tempdata التي تسمح لوحدة التحكم الخاصة بك بتسليم البيانات إلى وحدة تحكم أخرى بعد إعادة توجيه. إنه في الواقع متغير جلسة (أو ملف تعريف الارتباط إذا قمت بتكوينه على هذا النحو) ولكن يتم تنظيفه تلقائيا بعد الطلب التالي.

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

لذلك إذا كان لدينا نموذج مستخدم مع الخصائص: اسم المستخدم، واللمس الكامل، والبريد الإلكتروني، يمكننا القيام بما يلي في العرض:

<%= Html.ValidationSummary() %>

<% using (Html.BeginForm()) { %>
  <fieldset>
    <legend>User details</legend>
    <%= Html.AntiForgeryToken() %>

    <p>
      <label for="Username">Username:</label>
      <%= Html.Textbox("Username", Model.Username, "*") %>
    </p>
    <p>
      <label for="FullName">FullName:</label>
      <%= Html.Textbox("FullName", Model.FullName, "*") %>
    </p>
    <p>
      <label for="Email">Email:</label>
      <%= Html.Textbox("Email", Model.Email, "*") %>
    </p>
    <p>
       <input type+"submit" value="Save user" />
    </p>
  </fieldset>
<% } %>

سنحصل بعد ذلك على إجراءات تحكم تعرض هذه الرأي، واحدا للحصول على وآخر للنشر:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult User()
{
  return View(new User())
}

[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult User([Bind(Include = "Username,FullName,Email")]User user)
{
   if (!ModelState.IsValid()) return View(user);

   try
   {
     user.save()
     // return the view again or redirect the user to another page
   }
   catch(Exception e)
   {
     ViewData["Message"] = e.Message;
     return View(user)
   }
}

هل هذا ما كنت تبحث عنه؟ أو هل ترغب في الحفاظ على حالة النماذج التي لا يتم عرضها في نموذج بين الطلبات؟

الشيء الرئيسي الذي يجب تذكره هو أن التعليمات البرمجية الخاصة بك ينفذ على الخادم طوال مدة الطلب والغايات، والمعلومات الوحيدة التي يمكنك تمريرها بين طلباتك هي بيانات نموذج HTML الأساسية ومعلمات URL ومعلومات الجلسة.

كما ذكر أشخاص آخرون، أود أن أوصي بشدة إلى إطار ستيف ساندرران برو ASP.NET MVC لفهم كامل للعمل مع إطار MVC.

  • الحقول الخفية، مثل:

    <% using (Html.BeginForm<SomeController>(c=>c.SomeAction(null))) {%>
      <%= Html.Hidden("SomeField", Model.SomeField)%>
      <%= Html.Hidden("AnotherField", Model.AnotherField)%>
    
  • تحديد النموذج المحدد وليس له أي حقول صريحة (تعطي الحقول المخفية لك). في المثال أدناه، يتم ملء النموذج بواسطة وحدة التحكم مع القيم المستلمة من آخر مشاركة، بحيث تمكن هذا خيار لا js في الصفحة التي يمكن أن تصفية بناء على الحالة:

    Some Filter: <% using( Html.BeginForm<SomeController>(
            c => c.SomeAction(model.SomeField, model.AnotherField, model.YetAnotherField, null, model.SomeOtherField)
            )) { %>
                <%= Html.DropDownList("status", Model.StatusSelectList)%>
                <input type="submit" value="Filter" class="button" />
                <% } %>
    
  • استخدم طرق التمديد لإنشاء حقول، إذا كنت تريد ملء الحقول بالقيم المنشورة عند إظهار رسائل التحقق من الصحة الفاشلة على النموذج المقدم
  • على ASP.NET MVC 2 قدموا طريقة لإنقاذ مثيل في حقل مخفي ... المشفرة + (أعتقد) الموقع
  • Tempdata إذا كان كل ما ذكر أعلاه لا يفعل ذلك (يمر عبر الجلسة - تنظيفها في الطلب التالي)
  • كما ذكرت، عند استخدام Ajax الحالة موجودة بالفعل في الحقول المحملة مسبقا في موقع العميل. إذا كنت بحاجة إلى القيام بمكافحة كاملة، فقم بتحديث أي مجال قد تحتاج إليه مع JS الخاص بك.

ما سبق جميع خيارات مستقلة مختلفة لتحقيق ذلك يمكن استخدامه في سيناريوهات مختلفة. هناك المزيد من الخيارات لم أذكر أي ملفات تعريف الارتباط، جلسة، تخزين الاشياء في DB (مثل لمعالج خطوة متعددة غير قابل للاسترداد)، مرت المعلمات إلى إجراء. لا توجد آلية واحدة لحكمها جميعا، ولا ينبغي أن يكون هناك.

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

أولا أحتاج إلى بعض الأساليب التي تجعل الأمور أسهل:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using LuvDaSun.Extensions;
using System.Web.UI;

namespace LuvDaSun.Web.Mvc
{
    public static class HtmlHelperExtensions
    {
        static LosFormatter _losFormatter = new LosFormatter();
        public static string Serialize(this HtmlHelper helper, object objectInstance)
        {
            var sb = new StringBuilder();
            using (var writer = new System.IO.StringWriter(sb))
            {
                _losFormatter.Serialize(writer, objectInstance);
            }
            return sb.ToString();
        }


    }

    [AttributeUsage(AttributeTargets.Parameter)]
    public class DeserializeAttribute : CustomModelBinderAttribute
    {
        public override IModelBinder GetBinder()
        {
            return new DeserializeModelBinder();
        }
    }

    public class DeserializeModelBinder : IModelBinder
    {
        static LosFormatter _losFormatter = new LosFormatter();

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType.IsArray)
            {
                var type = bindingContext.ModelType.GetElementType();
                var serializedObjects = (string[])bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string[]));
                var deserializedObjects = Array.CreateInstance(bindingContext.ModelType.GetElementType(), serializedObjects.Length);

                for (var index = 0; index < serializedObjects.Length; index++)
                {
                    var serializedObject = serializedObjects[index];
                    var deserializedObject = _losFormatter.Deserialize(serializedObject);

                    deserializedObjects.SetValue(deserializedObject, index);
                }

                return deserializedObjects;
            }
            else
            {
                var serializedObject = (string)bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string));
                var deserializedObject = _losFormatter.Deserialize(serializedObject);

                return deserializedObject;
            }
        }
    }

}

ثم في جهاز التحكم الخاص بي لدي شيء من هذا القبيل (لتحديث منتج)

    public ActionResult Update(string productKey)
    {
        var model = _shopping.RetrieveProduct(productKey);

        return View(model);
    }
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Update([Deserialize]Shopping.IProduct _model, FormCollection collection)
    {
        UpdateModel(model);

        model.Save();

        return RedirectAfterPost();
    }

وأحتاج إلى حقل مخفي يحمل الكائن المتسلسل في النموذج:

    <% 
        using (Html.BeginRouteForm("Product", FormMethod.Post, new { id = UniqueID, }))
        {
    %>
<%= Html.Hidden("Model", Html.Serialize(Model)) %>
    <h1>
        Product bewerken</h1>
    <p>
        <label for="<%=UniqueID %>_Name">
            Naam:</label>
        <input id="<%=UniqueID %>_Name" name="Name" type="text" value="<%= Html.AttributeEncode(Model.Name) %>"
            class="required" />
        <br />
    </p>
    <p>
        Omschrijving:<br />
        <textarea id="<%= UniqueID %>_Description" name="Description" cols="40" rows="8"><%= Html.Encode(Model.Description) %></textarea>
        <br />
    </p>
    <p>
        <label for="<%=UniqueID %>_Price">
            Prijs:</label>
        <input id="<%= UniqueID %>_Price" name="Price" type="text" value="<%= Model.Price.ToString("0.00") %>"
            class="required" />
        <br />
    </p>
    <ul class="Commands">
        <li><a href="" class="ClosePopup">Annuleren</a></li>
        <li>
            <input type="submit" value="Opslaan" /></li>
    </ul>
    <% 
        } 
    %>

    <script type="text/javascript">

        jQuery('#<%= UniqueID %>').validate();

    </script>

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

لاحظ أنه يجب تزيين الكائن الذي تقوم به تسلسله بسمة Serializable أو يجب أن يكون لديك typeconverter يمكنه تحويل الكائن إلى سلسلة.

يتم استخدام العرض LosFormatter (تسلسل الكائنات المحدودة) من قبل ViewState في WebForms. كما يوفر التشفير من بيانات التسلسل.

تحية...

مكالمات AJAX هي ما نفعله. إذا كنت تتحدث عن الشبكات بشكل عام، تحقق من jqgrid. وكيف يوصيون بتنفيذ AJAX.

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