390 likes | 506 Vues
Umzug ASP.NET- WebForms -Elemente in MVC weiterverwenden. Dr. Malte Clasen adesso AG. Über uns. Malte Clasen Softwareentwickler http://malteclasen.de adesso AG IT-Dienstleister http://adesso.de. Rezeptefuchs.de. Rezeptefuchs.de. Gegeben: WebForms -Anwendung. Controls (Code)
E N D
UmzugASP.NET-WebForms-Elemente in MVC weiterverwenden Dr. Malte Clasen adesso AG
Über uns • Malte ClasenSoftwareentwicklerhttp://malteclasen.de • adesso AGIT-Dienstleisterhttp://adesso.de
Gegeben: WebForms-Anwendung • Controls (Code) • Controls (ASCX) • Pages (ASPX)
WebForms in MVC einbetten • Lifecycle von WebForms und MVC praktisch nicht vereinbar • Komplexität in WebForms-Anwendungen in Controls gebündelt • Controls in MVC einbetten • sinnvoll für Elemente, die für sich stehen können • ungeeignet bei Interaktion mit dem Rest der Seite
Ansatz • Eingabe: HttpRequest • Ausgabe: HttpResponse • WebForms-Aufruf simulieren • HttpRequest direkt übergeben, wird nicht verändert • HttpResponse neu erstellen und die erzeugte Ausgabe in die MVC-Ausgabe integrieren
Vereinfachungen • nur ein Control pro HTML-Seite • sonst gesonderte Behandlung des form-Tags notwendig • nur Controls, keine Pages • Pages entweder in den folgenden Code einflechten, oder • Pages in ASCX-Controls umwandeln • nur Form, kein Head • kann analog aus dem HTML-Code übertragen werden
Quellcode • https://github.com/malteclasen/MvcMigration.git
Controller private ControlCreateItem(Page page); publicvirtualActionResult Index() { varitem =WebFormsHelper.RenderLegacyItem(CreateItem, HttpContext, PageUrl); ViewBag.ControlHtml= item.ControlHtml; returnView("LegacyItem"); } • Controller.Index()
Code-Control privateControlCreateItem(Pagepage) { returnnewWebForms.MyControl(); } • CreateItem() • Controller.Index()
ASCX-Control • ascx als Embedded Resource privateControlCreateItem(Pagepage) { returnpage.LoadControl( "~/bin/WebForms.dll/" + "WebForms.MyWebUserControl.ascx"); } • CreateItem() • Controller.Index()
Global.asax protectedvoidApplication_Start() { … HostingEnvironment. RegisterVirtualPathProvider( newEmbeddedResourcePathProvider()); … } • Application_Start()
Controller publicvirtualActionResult Index() { varitem =WebFormsHelper.RenderLegacyItem(CreateItem, HttpContext, PageUrl); ViewBag.ControlHtml= item.ControlHtml; returnView("LegacyItem"); } • Controller.Index()
WebFormsHelper.RenderLegacyItem() publicstaticItemContentRenderLegacyItem( Func<Page, Control> contentCreator) { varpage = CreatePage(); varcontent = contentCreator(page); page.AddControl(content); varwriter= newStringWriter(); varresponse = ProcessRequest(page, writer); … • WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.RenderLegacyItem() … TransferCookies(response, HttpContext.Current.Response); varform = GetForm( Clean(stringWriter.ToString())); returnnewItemContent { ControlHtml= form, }; } • WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.CreatePage() privatestaticContainerPageCreatePage() { varpage = newContainerPage{ RenderingCompatibility=newVersion(3, 5), ClientIDMode=ClientIDMode.AutoID, }; varscriptManager = newScriptManager { … } AddDefaultScripts(scriptManager); page.AddControl(scriptManager); page.AddHead(newContentPlaceHolder{ ID = "HeadContent"}); returnpage; } • WFH.CreatePage()WFH.RenderLegacyItem()Controller.Index()
ContainerPage privateclassContainerPage : Page { privateHtmlForm_form = newHtmlForm(); privateHtmlHead_head = newHtmlHead(); protectedoverridevoidOnInit(EventArgs e) … publicvoidAddHead(Controlcontrol) … publicvoidAddControl(Controlcontrol) … privateHttpSessionState _session; publicoverrideHttpSessionStateSession … } • WFH.CreatePage()WFH.RenderLegacyItem()Controller.Index()
ContainerPage.OnInit() protectedoverridevoidOnInit(EventArgs e) { base.OnInit(e); varhtml = newHtmlGenericControl("html"); Controls.Add(html); html.Controls.Add(_head); varbody = newHtmlGenericControl("body"); html.Controls.Add(body); _form.Enctype = "multipart/form-data"; body.Controls.Add(_form); } • CP.OnInit()WFH.CreatePage()WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.CreatePage() privatestaticContainerPageCreatePage() { varpage = newContainerPage{ RenderingCompatibility=newVersion(3, 5), ClientIDMode=ClientIDMode.AutoID, }; varscriptManager = newScriptManager { … } AddDefaultScripts(scriptManager); page.AddControl(scriptManager); page.AddHead(newContentPlaceHolder{ ID = "HeadContent"}); returnpage; } • WFH.CreatePage()WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.AddDefaultScripts() privatestaticvoidAddDefaultScripts( ScriptManagerscriptManager) { scriptManager.Scripts.Add(newScriptReference {Name = "MsAjaxBundle"}); scriptManager.Scripts.Add(newScriptReference {Name = "WebForms.js", Assembly = "System.Web", Path = "~/Scripts/WebForms/WebForms.js" }); … } • WFH.AddDefaultScripts()WFH.CreatePage()WFH.RenderLegacyItem()Controller.Index()
App_Start\BundleConfig publicclassBundleConfig { publicstaticvoidRegisterBundles( BundleCollectionbundles) { bundles.Add( newScriptBundle("~/bundles/MsAjaxJs") .Include( "~/Scripts/WebForms/MsAjax/MicrosoftAjax.js", … )); } • BC.RegisterBundles()
WebFormsHelper.RenderLegacyItem() publicstaticItemContentRenderLegacyItem( Func<Page, Control> contentCreator) { varpage = CreatePage(); varcontent = contentCreator(page); page.AddControl(content); varwriter= newStringWriter(); varresponse = ProcessRequest(page, writer); … • WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.ProcessRequest() privatestaticHttpResponseProcessRequest( IHttpHandlerpage, TextWriterwriter) { varresponse = newHttpResponse(writer); varcontext = newHttpContext( HttpContext.Current.Request, response); context.SetSessionStateBehavior( SessionStateBehavior.Required); page.ProcessRequest(context); returnresponse; } • WFH.ProcessRequest()WFH.RenderLegacyItem()Controller.Index()
ContainerPage.Session publicoverrideHttpSessionState Session { get { return_session ?? (_session = GetMockHttpSessionState()); } } • CP.Session • WFH.ProcessRequest()WFH.RenderLegacyItem()Controller.Index()
ContainerPage.GetMockHttpSessionState privatestaticHttpSessionState GetMockHttpSessionState() { varstaticObjects = newHttpStaticObjectsCollection(); varitemCollection = newSessionStateItemCollection(); IHttpSessionStatesessionStateContainer = newHttpSessionStateContainer(…); … • CP.GetMockHttpSessionState() • CP.SessionWFH.ProcessRequest()WFH.RenderLegacyItem()Controller.Index()
ContainerPage.GetMockHttpSessionState varstate = (HttpSessionState) Activator.CreateInstance( typeof(HttpSessionState), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance| BindingFlags.CreateInstance, null, newobject[] { sessionStateContainer }, CultureInfo.CurrentCulture); returnstate; } • CP.GetMockHttpSessionState() • CP.SessionWFH.ProcessRequest()WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.RenderLegacyItem() … TransferCookies(response, HttpContext.Current.Response); varform = GetForm( Clean(stringWriter.ToString())); returnnewItemContent { ControlHtml= form, }; } • WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.TransferCookies() privatestaticvoidTransferCookies( HttpResponsesource, HttpResponse target) { foreach(var cookie in source.Cookies.Cast<string>() .Select(key => source.Cookies[key]) .Where(cookie => cookie != null)) { target.Cookies.Add(cookie); } } • WFH.TransferCookies()WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.RenderLegacyItem() … TransferCookies(response, HttpContext.Current.Response); varform = GetForm( Clean(stringWriter.ToString())); returnnewItemContent { ControlHtml= form, }; } • WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.Clean() privatestaticstring Clean(string source) { returnsource.Replace( " ", " "); } • WFH.Clean()WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.RenderLegacyItem() … TransferCookies(response, HttpContext.Current.Response); varform = GetForm( Clean(stringWriter.ToString())); returnnewItemContent { ControlHtml= form, }; } • WFH.RenderLegacyItem()Controller.Index()
WebFormsHelper.GetForm() privatestaticstringGetForm(stringrendered) { conststringformStartTag = "<form"; conststringformEndTag = "</form>"; varformStart= rendered.IndexOf(formStartTag); varformEnd = rendered.LastIndexOf(formEndTag); varform = rendered.Substring(formStart, formEnd-formStart+formEndTag.Length); returnform; } • WFH.GetForm()WFH.RenderLegacyItem()Controller.Index()
Controller publicvirtualActionResult Index() { varitem =WebFormsHelper.RenderLegacyItem(CreateItem, HttpContext, PageUrl); ViewBag.ControlHtml= item.ControlHtml; returnView("LegacyItem"); } • Controller.Index()
View @Html.Raw(ViewBag.ControlHtml)
Zusammenfassung • Control laden, ASCX aus Embedded Resource • HttpContext und Page erzeugen • Page.ProcessRequest aufrufen • Cookies transferieren • HTML-Code an View übergeben • Quellcode auf https://github.com/malteclasen/MvcMigration.git
Vielen Dank! Dr. Malte Clasen adesso AG
Firma • mein Blog: http://malteclasen.de/blog • mein Arbeitgeber: http://adesso.de • Stellenangebote: http://www.aaajobs.de/