إنشاء مثيل ASPX صفحة التحكم ASCX في فئة نهاية الظهر دون تحميل FilePath

StackOverflow https://stackoverflow.com/questions/1325101

  •  19-09-2019
  •  | 
  •  

سؤال

سؤال: هل من الممكن في الكود النهائي الخلفي (ليس في الرمز وراء ولكن في فئة نهاية الظهر الفعلية) لتحميل وجعل صفحة أو عنصر تحكم محددة في .aspx أو .ascx دون الحاجة إلى استخدام الحمل (المسار) وبدلا من ذلك فقط إنشاء مثيل للصفحة / عنصر التحكم؟

أريد أن أكون قادرا على القيام بذلك (من فئة النهاية الخلفية وليس رمز خلف):

MyControl myCtl = new MyApp.Views.Shared.MyControl();
String html = Util.ControlToString(myCtl); //I get an empty string & hidden errors

بدلا من هذا

public static string ControlToString(string path)
{
    Page pageHolder = new Page();
    MyControl myCtl = (MyControl)pageHolder.LoadControl(path);
    pageHolder.Controls.Add(myCtl);
    StringWriter output = new StringWriter();
    HttpContext.Current.Server.Execute(pageHolder, output, false);
    return output.ToString();
}

تفاصيل:في ASP.NET WebApp، أحتاج أحيانا إلى تقديم عنصر تحكم مستخدم (.ascx) أو الصفحة (.aspx) كسلسلة HTML. عندما تروع صفحة أو عنصر تحكم من رمز خلفه، يظهر فئتها في Intellisense في رمز نهاية ظهري، ويمكنني إنشاء مثيل وتعيين خصائص دون الحصول على تجميع أخطاء وقت التشغيل أو تشغيل الوقت. ومع ذلك، عندما أحاول تقديم الصفحة أو التحكم في التحول، أحصل دائما على سلسلة فارغة وعند التفتيش، تظهر الصفحة أو التحكم في أخطاء التقديم الداخلية المكبوتة إلا إذا قمت بتحميل الصفحة أو التحكم باستخدام مسار الملفات الفعلية.

أعتقد أن القضية الرئيسية يجب أن تفعل مع متى وكيف يتم تشغيل ملفات .aspx / .ascx. لا أريد إنشاء مكتبة فئة مترجمة مسبقا لأجهزة التحكم في المستخدم لأن ذلك من شأنه أن يجعل عملية التصميم محرجا وأنا أحب ميزات المصمم التي تقدمها صفحات .aspx / .ascx ولذا أحب أن أجد طريقة ل اجعل الصفحات تجميعها في الحل بحيث تكون قابلة للاستخدام مثل أي فئة نهاية ظهر أخرى ولكن لا يزال بإمكانها إنشاءها باستخدام المصمم. أريد أن تكون أفضل ما في العالمين (1) لتتمكن من تحرير الصفحات والضوابط في المصمم و (2) إنشاء مثيلات وتعيين خصائصها باستخدام فئات نهاية الظهر.

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

المحلول

فيما يلي نهج قد يساعد في حالات مثل هذا.

قد لا يعرف رمز "النهاية الخلفية" حيث يوجد عنصر تحكم المستخدم، لكن عنصر تحكم المستخدم يعرف أين هو.

لذلك، في عنصر تحكم المستخدم، أضف طريقة ثابتة مثل هذا:

public partial class MyControl : UserControl
{
  ...
  public static MyControl LoadControl(CustomDto initialData)
  {
    var myControl = 
        (MyControl) 
        ((Page) HttpContext.Current.Handler)
        .LoadControl("~\\UserControlsSecretPath\\MyControl.ascx");
    myControl._initialData = initialData;
    return myControl;
  }
  ...
  private CustomDto _initialData;
}

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

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

في الرمز الخلفي الخاص بك، أو في أي مكان آخر، يمكنك القيام بشيء ما:

var control = MyControl.LoadControl(customDto);
PlaceHolder1.Controls.Add(control);

نصائح أخرى

بشكل عام: لا.

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

بالنسبة لمواقع الويب المعتمدة التي تقوم بها ASP.NET هذه التعليمات البرمجية كجزء من .dll .dll مقدما مسبقا، وهذا هو السبب في تحميل هذه المواقع أسرع. ومع ذلك، فإن IIRC ستظل بحاجة إلى إنشاء مثيل ولدت الطبقات بدلا من الفصول الأصلية الخاصة بك.

إنه طلب شائع للغاية، ولكن حتى الآن لم تقدم MS الأدوات للقيام بذلك.

يحرر: على الرغم من أنني فشلت في معرفة سبب رغبتك في تقديم عنصر تحكم إلى سلسلة في الذاكرة، فقد يكون لدي حل لمشاكل البناء.

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

ومع ذلك، يجب وضع شفرة مشتركة (أي مشتركة بين مشروع عناصر التحكم والمشروع الرئيسي) في مشروع مكتبة منفصل، حتى تتمكن من تجميع كل مشروع بشكل منفصل دون اعتبارات

استخدام LoadControl داخل المشروع الرئيسي سوف تجميعها على الطاير (الكود الخلف ممكن)؛ إذا كنت بحاجة إلى تعيين خصائص، فيجب عليك تحديد الواجهات في المشروع المشترك، وتنفذها على عناصر تحكم المستخدم المناسبة وإلقاء التحكم الذي تم إنشاؤه بواسطة LoadControl إلى الواجهة المناسبة.

قمت بتطوير حل يحل مشكلتي في مقابل 2008:

  1. إنشاء حل الموقع الرئيسي: إنشاء حل موقع MVC 1 في VS 2008
  2. إنشاء مكتبة فئة النموذج: أضف مكتبة فئة لرمز النموذج
  3. إنشاء رمز عرض: أضف "موقعا فارغا" لعقد صفحات .ascx وإضافة مرجع مكتبة النموذج
  4. إنشاء موقع النشر: أضف مشروع النشر الذي يجمع "موقع الويب الفارغ" يوم "خصائص الصفحة" و يفحص: "دمج جميع المخرجات في تجميع واحد" و "علاج كمكتبة" وتأكد من إلغاء تحديد: "اسمح لهذا الموقع مسبقا أن يكون قابلا للتحديث"
  5. إخراج النشر المرجعي: في المشروع الرئيسي، أضف إشارة إلى إخراج موقع النشر.
  6. ASP. - ضوابط مجمعة: الضوابط تظهر تحت ASP. مساحة الاسم وسميت بطريقتين A. إذا لم تعلن صفحة .ascx / ASPX "اسم Classname"، فهي تسمى باستخدام مجلدها واسم الملف مع الشرطة السفلية. <٪ @ لغة التحكم = "C #" classname = "admin_index"٪> b. إذا قاموا بإعلان اسم فئة إذن اسمهم

  7. قائمة الاغراض

الاستعمال: مثال رمز أدناه

هنا مثال على ذلك

public ActionResult Index()
{
    var ctl = new ASP.Directory_FirmProfile();  //create an instance
    ctl.Setup(new MyDataModel);                 //assign data

    //string test = CompiledControl.Render(ctl); //output to string
    return new HtmlCtl.StrongView(ctl);         //output to response
}    



   public class CompiledControl
    {
        public static string Render(Control c)
        {
            Page pageHolder = new Page();
            pageHolder.Controls.Add(c);
            StringWriter output = new StringWriter();
            HttpContext.Current.Server.Execute(pageHolder, output, false);
            return output.ToString();
        }

        public static void Render(Control c, StringWriter output)
        {
            Page pageHolder = new Page();
            pageHolder.Controls.Add(c);
            HttpContext.Current.Server.Execute(pageHolder, output, false);
        }

        public static void Render(Control c, HttpResponseBase r)
        {
            Page pageHolder = new Page();
            pageHolder.Controls.Add(c);
            HttpContext.Current.Server.Execute(pageHolder, r.Output, false);
        }


    }


    public class StrongView : ActionResult
    {
        private Control ctl;
        public StrongView(Control ctl)
        {
            this.ctl = ctl;
        }

        public string VirtualPath{get;set;}


        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");

            HtmlCtl.CompiledControl.Render(ctl, context.HttpContext.Response);

        }
    }

لقد جئت مع حل أبسط على غرار نصيحة روبن. عملت دون مشاكل لمدة شهر تقريبا:

//Example usage

//reference the control
var emailCTL = new HtmlCtl.ControlOnDisk<MyControlType>(@"~\Views\EmailTemplates\MyControlType.ascx");

//if you have a code behind you will get intellisense allowing you to set these properties
// and re-factoring support works most places except the template file. 
emailCTL.c.title = "Hello World "; //title is a property in the code behind
emailCTL.c.data = data; //data is a property in the code behind

string emailBody = emailCTL.RenderStateless(); 



//Helper Class
    public class ControlOnDisk<ControlType> where ControlType : UserControl
    {
        public ControlType c;
        Page pageHolder = new Page();
        public ControlOnDisk(string path)
        {
            var o = pageHolder.LoadControl(path);
            c = (ControlType)o;
            pageHolder.Controls.Add(c);
        }

        public string RenderStateless()
        {

            StringWriter output = new StringWriter();

            // set up dumby context for use in rendering to email stream
            StringBuilder emailMessage = new StringBuilder();
            TextWriter tw = new StringWriter(emailMessage);
            HttpResponse dumbyResponse = new HttpResponse(tw);
            HttpRequest dumbyRequest = new HttpRequest("", "http://InsertURL.com/", ""); //dummy url requierd for context but not used
            HttpContext dumbyContext = new HttpContext(dumbyRequest, dumbyResponse);
            //HttpContextBase dumbyContextBase = new HttpContextWrapper2(dumbyContext);

            dumbyContext.Server.Execute(pageHolder, output, false);
            return output.ToString();

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