인스턴스 만들기 페이지의 Ascx 제어에서 다시 끝없는 클래스 로드 FilePath
-
19-09-2019 - |
문제
질문: 그것은 다시 끝 코드 (지에서 뒤에 코드 하지만 실제 백 end class) 을 로드하고 렌더링하기 위해 페이지 또는 통제에 정의된다.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 웹 애플리케이션 내가 때때로 필요하 렌더링에 사용자 정의 컨트롤(.ascx)또는 페이지는(.aspx)HTML 문자열입니다.페이지 또는 통제에서 상속 코드,뒤에 해당 클래스에 표시 intellisense 에 다시 끝 코드가 인스턴스를 만들 수 있고 속성을 설정 없이 컴파일시 혹은 실행시 오류가 있습니다.그러나려고 할 때 페이지를 렌더링하거나 제어 나는 언제나 빈 문자열에 따라 검사 페이지나 컨트롤의 보 억제 내 오류를 렌더링하지 않는 한 나는 페이지를 로드하거나 제어를 사용하여 실제 파일 경로.
내가 생각하는 중요한 문제와 함께 할 때&하는 방법.aspx/.ascx 파일은 런타임을 컴파일합니다.나는 원하지 않을 만들 미리 컴파일 클래스 라이브러리의 사용자 정의 컨트롤는 것이기 때문에 디자인을 만들 어색한 프로세스와 정말 좋아한 디자이너 기능을 제공.aspx/.ascx 페이지와 그래서 나는 사랑을 만들 수 있는 방법을 찾아 페이지에서 컴파일하도록 솔루션들은 사용 가능한과 같은 다른 어떤 다시 end class 지만 여전히 수 있을 사용하여 만든 디자이너입니다.내가 원하는 두 세계의 최고의(1)할 수 있는 페이지를 편집하고 컨트롤 디자이너 그리고(2)인스턴스를 만들고 속성을 설정합니다 다시 사용하여 종료됩니다.
해결책
여기에 접근 방식에 도움이 될 수 있는 상황은 이렇습니다.
"Back-end"코드가 어디 있는지 알 수 없습니다 사용자 정의 컨트롤에 위치하고 있지만,사용자 정의 컨트롤가 알고있는 곳입니다.
그래서,사용자 정의 컨트롤 추가 정적 방법을 다음과 같다:
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
이 포함되어 있는 방법을 설명하기 위해 초기 데이터를 전달할 수 있는 사용자가 제어할 수 있습니다.당신이 할 필요가 없는 것,그것을 밖으로!)
이와 함께,로드하는 코드 사용자 컨트롤 지 을 알 필요가있는 경로를 사용자 정의 컨트롤 물리적 위치.는 경우에는 위치도 변경,그 후 업데이트나 위치에 있습니다.다른 모든 코드를 사용하는 이 정렬은 변경되지 않습니다.
에서 당신의 뒤쪽 끝 코드,또는 다른 곳에서,당신이 무언가를 할 수 있다:
var control = MyControl.LoadControl(customDto);
PlaceHolder1.Controls.Add(control);
다른 팁
일반적으로 말하기 : 아니요.
내가 아는 한, ASP.net은 상속합니다 수업에서 .aspx/.ascx 템플릿을 코드와 결합합니다. 이것이 컨트롤이 비어있는 이유입니다. 템플릿을 코드와 결합하는 코드가 누락되었습니다. 이는 일반적으로 ASP.NET에 의해 페이지 나 사용자 컨트롤에 처음 액세스 할 때 수행됩니다 (정확히 첫 번째 히트가 약간 느린 이유입니다. 실제로 훅 업 코드를 생성하고 컴파일하는 것입니다).
사전 컴파일 된 웹 사이트의 경우 ASP.NET은 사전 컴파일 된 웹 사이트의 .dll의 일부로이 코드를 생성하므로 이러한 사이트가 더 빠르게로드됩니다. 그러나 IIRC는 여전히 인스턴스화해야합니다 생성 원래 수업이 아닌 수업.
그것은 매우 일반적인 요청이지만 지금까지 MS는이를 수행 할 도구를 제공하지 않았습니다.
편집하다: 왜 당신이 메모리 내 문자열에 컨트롤을 렌더링하고 싶은지 알지 못하지만 빌드 문제에 대한 해결책이있을 수 있습니다.
비 컴파일 된 .ASCX 파일 (웹 응용 프로그램 모델이 아닌 웹 사이트 모델 사용)을 고수하는 경우 실제로 주요 프로젝트의 하위 폴더에 물리적으로 배치하여 별도로이를 개별적으로 개발하고 컨텐츠 파일로만 취급 할 수 있습니다. 그런 다음이 하위 폴더를 루트 폴더로 별도의 프로젝트를 만들 수 있습니다. 이 하위 폴더의 파일을 웹 사이트 파일로만 처리하면 기본 프로젝트는 여전히 웹 응용 프로그램 일 수 있습니다. (실제로 추천, '주 프로젝트에 포함 된 .csproj 파일을 원하지 않기 때문입니다.)
그러나 공유 코드 (즉, 컨트롤 프로젝트와 기본 프로젝트간에 공유)는 별도의 라이브러리 프로젝트에 넣어야하므로 상호 의존성없이 각 프로젝트를 별도로 컴파일 할 수 있습니다.
사용 LoadControl
메인 프로젝트 내에서는이를 즉석에서 컴파일 할 것입니다 (뒤의 코드가 가능). 속성을 설정 해야하는 경우 공유 프로젝트에서 인터페이스를 정의하고 적절한 사용자 컨트롤에서 구현하고 LoadControl
적절한 인터페이스에.
2008 년 vs에서 내 문제를 해결하는 솔루션을 개발했습니다.
- 주요 사이트 솔루션 작성 : VS 2008에서 MVC 1 웹 사이트 솔루션을 만듭니다
- 모델 클래스 라이브러리 만들기 : 모델 코드에 대한 클래스 라이브러리를 추가하십시오
- 보기 코드 작성 : .ASCX 페이지를 보유하려면 "빈 웹 사이트"를 추가하고 모델 라이브러리를 참조하십시오.
- 배포 사이트 작성 : "빈 웹 사이트"를 컴파일하는 배포 프로젝트 추가 "Properties Page"및 확인하다: "모든 출력을 단일 어셈블리로 병합"및 "라이브러리 구성 요소로 처리"하고 확실히 선택 취소: "이 사전 컴파일 된 사이트를 업데이트 할 수 있도록"
- 참조 배포 출력 : 메인 프로젝트에서는 배포 사이트의 출력에 대한 참조를 추가하십시오.
ASP. - 컴파일 된 컨트롤 : ASP 아래에 컨트롤이 나타납니다. 네임 스페이스와 두 가지 방식으로 명명되었습니다. A.ASCX / ASPX 페이지가 "클래스 이름"을 선언하지 않은 경우 폴더와 파일 이름을 밑줄과 함께 사용하여 명명됩니다. < %@ control language = "c#"classname = "admin_index" %> B. 클래스 이름을 선언 한 경우 그 이름입니다.
목록 항목
용법: 예제 코드는 다음과 같습니다
다음은 예제 사용법입니다
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();
}
}