我需要构建一个'可自定义的'asp.net web应用程序(不是asp.net mvc)。
我正在考虑使用IoC容器将用户控件注入aspx页面。
有人试过吗?
简而言之,我认为这是如何实现的:
我使用Scott Guthrie的方法构建可重用的“用户控件库”(请参阅他的文章“创建和使用用户控件库”)。
该库中的控件和页面应具有动态接收用户控件的位置(例如,在asp PlaceHolder中)。
在我的自定义Web应用程序中,我创建了特定的用户控件。
我将它们以某种方式放在IoC容器中,以便它们可以注入“用户控件库”的控件/页面中(例如,在PlaceHolders中)。
就是这样。
这基本上可以通过这里讨论的http://blogger.forgottenskies.com/?p=70来解决Spring.Net,但是要注入用户控件。
有没有人对这些东西有过一些经验?还是听起来很傻?替代方案?
我们的想法是可以在我的“用户控件库”之上构建不同的Web应用程序,而无需触及该库。
例如:在我的库中,我有一个包含4个文本框的页面,对于一个特定的应用程序,我需要添加一个文本框,而不更改页面的代码。我们的想法是在该页面中放置一个占位符,并在此占位符中动态注入我的自定义文本框。
答案 0 :(得分:4)
它与您的情况不完全相同,但我需要根据正在编辑的实体的运行时类型动态注入编辑器控件。我让所有的控件继承自这样的通用界面:
public interface IEditor
{
bool CanHandle(EntityBase entity);
void Display(EntityBase entity);
void Save(EntityBase entity);
}
public partial class AddressEditor : UserControl, IEditor
{
public bool CanHandle(EntityBase entity)
{
return (entity is Address);
}
public void Display(EntityBase entity)
{
var address = (Address)entity;
addressLine1Textbox.Text = address.Line1;
// etc...
}
public void Save(EntityBase entity)
{
var address = (Address)entity;
address.Line1 = addressLine1Textbox.Text;
// etc...
}
}
然后使用IoC容器(在本例中为StructureMap)我可以使用
之类的东西获得正确的用户控件var editorControl = ObjectFactory.GetAllInstancesOf<IEditor>().First(x => x.CanHandle(myEntity));
这就是它变得棘手的地方,如果您像这样创建一个实例,则无法向页面添加用户控件。您需要知道它的.ascx文件的位置。您可以通过编辑器界面公开它,以便每个控件都返回它:
public string AscxFile { get { return "~/UserControls/AddressEditor.ascx"; } } // Implements IEditor.AscxFile
然后在调用页面中,使用LoadControl:
var actualControl = LoadControl(editorControl.AscxFile);
editorPlaceholder.Controls.Add(actualControl);
editorControl.Display(myEntity);
我更喜欢使用复合控件,他们需要花费更多精力来创建,但无需担心.ascx文件,我可以直接将其添加到页面中:
var editorControl = ObjectFactory.GetAllInstancesOf<IEditor>().First(x => x.CanHandle(myEntity));
editorPlaceholder.Controls.Add((Control)editorControl);
editorControl.Display(myEntity);
确保你在Page.OnInit阶段添加控件,以便它可以参与ViewState,并且不会在回发之间记住它,所以你必须每次都这样做。
最后一步是使用您选择的IoC工具进行连接,我使用StructureMap自动加载IEditor
的所有实例,但我可以在应用程序代码或xml配置中的任何位置改变它。< / p>
答案 1 :(得分:1)
我们使用类似的模型构建了一套应用程序 我们有一个所谓的PageBuilder,它通过注入UserControls和WebParts构建每个页面。
一切都是可配置的(页面布局,页面控件,控件位置等),因此无需更改页面,UserControls或WebParts中的任何代码。 (除非需要添加/更改某些功能)。
我们甚至在控件中有配置和设置来根据SQL查询,模式,当前页面等各种方式更改行为。
基本上它的工作原理如下:
所有WebParts都可以通过自定义发布者/订阅者事件模型相互通信。即在WebPart A中,下拉选择被更改=&gt; WebPart B显示所选项目的数据。
该模型允许我们构建高度可配置的应用程序,客户可以在这些应用程序中设计布局和行为,而无需我们参与。
您的模型似乎是我们模型的一个子集,我只能说它很容易使用。从开发人员的角度和客户两方面来看。
修改强>
基本上,我们的框架包含一些调用PageBuilder的母版页和基页
每个母版页用于不同类型的对象:页面,用户控件,WebPart,灯箱等
每个aspx页面都包含一个PlaceHolder,用于UserControls和WebParts。这个PlaceHolder由PageBuilder填充。
我们的aspx页面中的UserControl / WebPart PlaceHolder可以填充我们想要的任何控件。因此根本不需要更改aspx页面。如果我们想要一个文本框,我们可以配置它。自定义UserControl或WebPart也是如此。通过这种方式,我们不需要为每个自定义应用程序重新创建aspx页面,但只需要更改配置。
我们为各种aspx页面提供了100多个UserControls和WebParts,但大多数aspx页面看起来类似于:
<%@ Page MasterPageFile="main.master" ... %>
<asp:Content runat="server" ContentPlaceHolderID="Main" ID="MainSection">
<asp:PlaceHolder runat="server ID="UserControlPlaceHolder"></asp:PlaceHolder>
</asp:Content>
在代码隐藏中我们有类似的东西:
Partial Class MyPageClass Inherits BasePage
Protected Sub Page_Init(ByVal sender As Object, ByVal e as System.EventArgs) Handles Me.Init
'The following method is in the BasePage and is part of the PageBuilder.
LoadControls()
End Sub
End Class
PageBuilder创建布局,然后加载并将所有控件和WebPart添加到正确的位置 (控制和控制位置的布局都是从配置中获取的。)
然后,PageBuilder为每个Control和WebPart应用设置。这些设置也是可配置的。设置可以是控件高度这样简单的事情,也可以是更复杂的事情,如“显示模式”(静态,页面相关,依赖于组等)。
希望这能更详细地解释它。