Erstellen Instanz Aspx Seite von Ascx Steuerung in einer Back-End-Klasse ohne Laden FilePath

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

  •  19-09-2019
  •  | 
  •  

Frage

Frage: Ist es möglich, in Back-End-Code (nicht in der Code-behind, aber in einer tatsächlichen Back-End-Klasse) laden und macht eine Seite oder Steuerung in einem ASPX oder .ascx definiert ohne Verwendung laden zu müssen (Pfad) und stattdessen nur eine Instanz der Seite / Steuerklasse erstellen?

Ich möchte in der Lage sein, dies zu tun (von einem Back-End-Klasse keinen Code hinter):

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

anstelle dieses

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();
}

Details: In einer Asp.net WebApp Ich brauche gelegentlich ein Benutzersteuerelement (ASCX) oder Seite (.aspx) als HTML-String zu machen. Wenn eine Seite oder Steuer erbt von einem Code-behind, bis seine Klasse zeigt in Intellisense in meinem Back-End-Code, und ich kann, ohne sich der Kompilierung oder Laufzeitfehler eine Instanz und Verformungseigenschaften erstellen. Allerdings, wenn ich versuche, die Seite zu machen oder zu steuern, hat sich immer einen leeren String und bei einer Überprüfung der Seite oder Steuer zeigt unterdrückt interne Rendering-Fehler, wenn ich die Seite oder Steuerung über seinen physischen Dateipfad laden.

ich denke, das Hauptproblem zu tun hat mit, wenn und wie die ASPX / ASCX-Dateien Laufzeit kompiliert werden. Ich will nicht eine vorge kompilierten Klassenbibliothek von Benutzersteuerungen erstellen, weil das den Design-Prozess umständlich und mir wirklich machen würde wie die Designer von den ASPX / ASCX Seiten angebotenen Funktionen und so würde ich gerne einen Weg finden, macht die Seiten in der Lösung zusammenstellen, so dass sie wie jede andere back-End-Klasse verwendbar sind, aber immer noch mit dem Designer erstellt werden können. Ich will das Beste aus beiden Welten (1) in den Designern zu bearbeiten Seiten und Steuerelemente der Lage sein, und (2) Instanzen erstellen und ihre Eigenschaften Back-End-Klassen.

War es hilfreich?

Lösung

Hier ist ein Ansatz, der in Situationen wie diesen helfen kann.

Die "Back-End" Code kann nicht wissen, wo der Benutzer die Kontrolle befindet, aber der User Control weiß, wo es ist.

Also, in der User Control, fügen Sie eine statische Methode wie folgt aus:

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;
}

(Der CustomDto ist enthalten, um darzustellen, wie Anfangsdaten können an die Benutzerkontrolle übergeben werden. Wenn Sie das nicht tun müssen, nehmen Sie es aus!)

Damit der Code, dass Lasten der Benutzersteuerung funktioniert nicht Notwendigkeit, den Weg, wo der Benutzer die Kontrolle zu wissen, physisch befindet. Wenn diese Position jemals ändert, dann aktualisieren, um diese einen Ort. Alle anderen Code, der diese Usercontrol verwendet, ist unverändert.

In dem Back-End-Code oder anderswo, können Sie dies etwas tun:

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

Andere Tipps

Generell gilt: Nr.

Soweit ich weiß, ASP.NET erbt von Klassen zu kombinieren, die ASPX / ASCX-Vorlage mit Ihrem Code. Deshalb ist Ihre Kontrollen zeigen leer: Der Code der Vorlage mit Ihrem Code zu kombinieren fehlt. Dies wird in der Regel von ASP.NET das erste Mal, wenn Sie eine Seite oder eine Benutzersteuerung zugreifen getan (die genau sind, warum der erste Treffer ein wenig langsam ist: es ist tatsächlich zu erzeugen und die Erstellung des hookup-Code).

Für vorkompilierte Websites ASP.NET generiert diesen Code als Teil Ihrer vorkompilierte Website DLL im Voraus, weshalb solche Seiten schneller laden. Allerdings IIRC werden Sie noch brauchen, um die erzeugt Klassen, anstatt Ihre ursprünglichen Klassen zu instanziiert.

Es ist ein ziemlich gemeinsamer Wunsch, aber bisher MS hat nicht die Werkzeuge zur Verfügung gestellt, dies zu tun.

Edit:. Auch wenn ich verstehe nicht, warum Sie ein Steuerelement mit einem In-Memory-String machen wollen würden, könnte ich eine Lösung für die Probleme mit dem Build hat

Wenn Sie nicht-kompilierten .ascx Dateien bleiben (mit dem Web-Site-Modell anstatt das Web-Anwendungsmodell), können Sie sie tatsächlich entwickeln getrennt, indem sie physisch in Unterordner des Hauptprojektes platzieren, und behandeln sie als Content-Dateien nur. Dann können Sie ein separates Projekt mit diesem Unterordner als Stammordner machen. Sie müssen nur die Dateien in diesem Unterordner als Web-Site-Dateien zu behandeln, kann das Hauptprojekt noch eine Web-Anwendung sein. (Eigentlich empfohlen, weil Sie nicht über die CSPROJ Dateien im Hauptprojekt enthalten sein sollen.)

Allerdings gemeinsamer Code (die zwischen den Kontrollen projizieren und dem Hauptprojekt geteilt ist) in einem separaten Bibliothek Projekt gestellt werden soll, so dass Sie jedes Projekt ohne Abhängigkeiten separat zusammenstellen können.

Mit LoadControl im Hauptprojekt wird sie schnell kompiliert (Code hinter möglich); wenn Sie Satz Eigenschaften benötigen, müssen Sie jedoch Schnittstellen in dem gemeinsamen Projekt definieren, implementieren sie auf die entsprechenden Bedienelemente und warf die Steuerung durch LoadControl an die entsprechende Schnittstelle erstellt.

entwickelte ich eine Lösung, die mein Problem in VS 2008 löst:

  1. Haupt Site Solution erstellen: Erstellen Sie eine Webseite MVC 1-Lösung in VS 2008
  2. Erstellen Modell-Klassenbibliothek: Fügen Sie eine Klassenbibliothek für das Model Code
  3. Erstellen Sie Code anzeigen: Fügen Sie ein "Empty Website" die .ascx Seiten zu halten, und fügen Sie einen Verweis auf die Modellbibliothek
  4. erstellen Deployment Site: Fügen Sie ein Bereitstellungsprojekt, das die "Empty Website" goto der "Eigenschaftenseite" kompiliert und Überprüfen : "Merge Alle Ausgänge in einer einzigen Baugruppe" und „Treat als Bibliothekskomponente“ und achten Sie darauf, deaktivieren : „Lassen Sie diese vorkompilierte Ort sein aktualisierbar“
  5. Referenz Deployment Ausgang: Im Hauptprojekt einen Verweis auf den Ausgang der Site Deployment hinzufügen.
  6. ASP. - Zusammengestellt Kontrollen: zeigen Kontrollen im Rahmen der ASP-up. Namespace und werden auf zwei Arten benannt      A. wenn die .ascx / aspx Seite hat eine „Classname“ nicht erklären, dann werden sie nannten ihre Ordner und Dateinamen mit Unterstrichen ex verwenden. <% @ Control Language = "C #" Classname = "admin_index" %>      B. wenn sie einen Klassennamen erklären haben, dann ist das der Name

  7. Liste item

Verwendung: Beispiel-Code ist unter

Hier ist ein Beispiel für die Verwendung

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);

        }
    }

Ich habe entlang der Linien von Ruben Rat mit einer einfacheren Lösung. Es hat funktioniert ohne Probleme für etwa einen Monat:

//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();

        }
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top