0

質問:バックエンドコード(コードビハインドではなく実際のバックエンドクラス)で、Load(path)を使用せずに、.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文字列としてレンダリングする必要がある場合があります。ページまたはコントロールがコードビハインドから継承する場合、そのクラスはバックエンドコードにインテリセンスで表示され、コンパイル時または実行時のエラーを発生させることなく、インスタンスを作成してプロパティを設定できます。ただし、ページまたはコントロールをレンダリングしようとすると、常に空の文字列が表示され、検査時に、物理ファイルパスを使用してページまたはコントロールをロードしない限り、ページまたはコントロールは抑制された内部レンダリングエラーを示します。

重要な問題は、.aspx/.ascxファイルが実行時にコンパイルされるタイミングと方法に関係していると思います。コンパイル済みのユーザーコントロールのクラスライブラリを作成したくないのは、デザインプロセスが煩雑になるためです。また、.aspx / .ascxページで提供されるデザイナー機能が本当に気に入っているので、次の方法を見つけたいと思います。ページをソリューションでコンパイルして、他のバックエンドクラスと同じように使用できるようにしますが、デザイナーを使用して作成することもできます。両方の長所を(1)デザイナーでページとコントロールを編集できるようにし、(2)インスタンスを作成し、バックエンドクラスを使用してそれらのプロパティを設定できるようにしたいと思います。

4

4 に答える 4

1

このような状況で役立つ可能性のあるアプローチを次に示します。

「バックエンド」コードはユーザーコントロールがどこにあるかを知らないかもしれませんが、ユーザーコントロールはそれがどこにあるかを知っています。

したがって、ユーザーコントロールで、次のような静的メソッドを追加します。

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は、初期データをユーザーコントロールに渡す方法を説明するために含まれています。必要がない場合は、データを取り出してください!)

これにより、ユーザーコントロールをロードするコードは、ユーザーコントロールが物理的に配置されている場所へのパスを知る必要がなくなりますその場所が変更された場合は、この1つの場所を更新してください。このUserControlを使用する他のすべてのコードは変更されていません。

バックエンドコードまたはその他の場所で、次のことを実行できます。

var control = MyControl.LoadControl(customDto);
PlaceHolder1.Controls.Add(control);
于 2010-03-09T20:58:05.067 に答える
0

一般的に言えば:いいえ。

私の知る限り、ASP.NETはクラスを継承して、.aspx/.ascxテンプレートをコードと結合します。これが、コントロールが空で表示される理由です。テンプレートとコードを組み合わせるためのコードがありません。これは通常、ページまたはユーザーコントロールに初めてアクセスするときにASP.NETによって実行されます(これが、最初のヒットが少し遅い理由です。実際には、フックアップコードを生成してコンパイルしています)。

プリコンパイルされたWebサイトの場合、ASP.NETは、プリコンパイルされたWebサイトの.dllの一部としてこのコードを事前に生成します。そのため、このようなサイトの読み込みが速くなります。ただし、IIRCでは、元のクラスではなく、生成されたクラスをインスタンス化する必要があります。

これはかなり一般的な要求ですが、これまでのところ、MSはこれを行うためのツールを提供していません。

編集:メモリ内の文字列にコントロールをレンダリングする理由がわかりませんが、ビルドの問題に対する解決策があるかもしれません。

コンパイルされていない.ascxファイル(WebアプリケーションモデルではなくWebサイトモデルを使用)に固執する場合は、メインプロジェクトのサブフォルダーに物理的に配置することで実際に個別に開発し、コンテンツファイルとしてのみ扱うことができます。次に、このサブフォルダーをルートフォルダーとして別のプロジェクトを作成できます。このサブフォルダー内のファイルをWebサイトファイルとして扱うだけで済みます。メインプロジェクトは引き続きWebアプリケーションにすることができます。(実際には、メインプロジェクトに.csprojファイルを含めたくないためです。)

ただし、共有コード(つまり、コントロールプロジェクトとメインプロジェクト間で共有される)は、相互に依存することなく各プロジェクトを個別にコンパイルできるように、個別のライブラリプロジェクトに配置する必要があります。

メインプロジェクト内で使用LoadControlすると、その場でコンパイルされます(コードビハインドが可能です)。ただし、プロパティを設定する必要がある場合は、共有プロジェクトでインターフェイスを定義し、それらを適切なユーザーコントロールに実装して、によって作成されたコントロールLoadControlを適切なインターフェイスにキャストする必要があります。

于 2009-08-24T22:37:53.473 に答える
0

私はVS2008で自分の問題を解決するソリューションを開発しました。

  1. メインサイトソリューションの作成:VS2008でMVC1Webサイトソリューションを作成します
  2. モデルクラスライブラリの作成:モデルコードのクラスライブラリを追加します
  3. ビューコードの作成: .ascxページを保持するための「空のWebサイト」を追加し、モデルライブラリへの参照を追加します
  4. 展開サイトの作成:「空のWebサイト」をコンパイルする展開プロジェクトを追加し、「プロパティ」ページに移動して、「すべての出力を1つのアセンブリにマージする」と「ライブラリコンポーネントとして扱う」をチェックし、必ずチェックを外します:「このプリコンパイルを許可する更新可能なサイト」
  5. デプロイメント出力の参照:メインプロジェクトで、デプロイメントサイトの出力への参照を追加します。
  6. ASP。-コンパイルされたコントロール:コントロールはASPの下に表示されます。名前空間と2つの方法で名前が付けられます。A。.ascx/aspxページで「ClassName」が宣言されていない場合は、フォルダとファイル名にアンダースコアを付けて名前が付けられます。<%@ Control Language = "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);

        }
    }
于 2009-09-01T13:39:15.237 に答える
0

私はルーベンのアドバイスに沿って、より簡単な解決策を考え出しました。それは約1ヶ月間問題なく動作しました:

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

        }
    }
于 2010-01-05T01:21:06.410 に答える