上回说到,我们配置了一下UnityConfig层,在这个层中定义了一个IContainerAccessor的接口和一个返回IUnityContainer类型的方法,这个方法的主要作用就是把Service层中的接口类和Business层中的接口实现类装配到UnityContainer中并返回,也就是指定那个接口实现类去实现某个接口类。
上回说到,我们配置了一下UnityConfig层,在这个层中定义了一个IContainerAccessor的接口和一个返回IUnityContainer类型的方法,这个方法的主要作用就是把Service层中的接口类和Business层中的接口实现类装配到UnityContainer中并返回,也就是指定那个接口实现类去实现某个接口类(晕,好像有点绕口啊)。

Xiaozhuang.UnityConfig
namespace Xiaozhuang.UnityConfig
{
public interface IContainerAccessor
{
IUnityContainer Container { get; }
}
public class UnityContainerConfig
{
public IUnityContainer GetIUnityContainer()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IQueryEmployeeService, QueryEmployeeBusiness>();
return container;
}
}
}
好了,现在终于轮到Web层了,要实现在Asp.Net页面中直接调用能够服务接口而不用从Unity容器中再去取出来,就要把Unity容器中的接口注入到页面中去,分两步走:第一步,在Global.Asax.cs中实现UnityConfig层中的IContainerAccessor接口,并把UnityConfig层返回的IUnityContainer赋值给实现接口的全局静态属性。

Code
namespace Xiaozhuang.Web


{
public class Global : System.Web.HttpApplication, IContainerAccessor

{


Members#region Members

private static IUnityContainer _container;

#endregion


Properties#region Properties


/**//// <summary>
/// The Unity container for the current application
/// </summary>
public static IUnityContainer Container

{
get

{
return _container;
}
set

{
_container = value;
}
}

#endregion


IContainerAccessor Members#region IContainerAccessor Members


/**//// <summary>
/// Returns the Unity container of the application
/// </summary>
IUnityContainer IContainerAccessor.Container

{
get

{
return Container;
}
}

#endregion


Application Events#region Application Events

protected void Application_Start(object sender, EventArgs e)

{
BuildContainer();
}

protected void Session_Start(object sender, EventArgs e)

{

}

protected void Application_BeginRequest(object sender, EventArgs e)

{

}

protected void Application_AuthenticateRequest(object sender, EventArgs e)

{

}

protected void Application_Error(object sender, EventArgs e)

{

}

protected void Session_End(object sender, EventArgs e)

{

}

protected void Application_End(object sender, EventArgs e)

{
CleanUp();
}
#endregion


Methods#region Methods

private static void BuildContainer()

{
UnityContainerConfig config = new UnityContainerConfig();
Container = config.GetIUnityContainer();
}
private static void CleanUp()

{

if (Container != null)

{

Container.Dispose();

}

}

#endregion
}
}
接下来要把UnityContainer中的接口注入到页面中去。建立一个BasePage的泛型类,先获取到从Gloab.Asax传过来的应用程序实例,转化为UnityContainer,利用BuildUp方法注入到页面中去。

BasePage
namespace Foresee.Web
{
public abstract class BasePage<T> : Page where T : class
{
protected override void OnPreInit(EventArgs e)
{
InjectDependencies();
base.OnPreInit(e);
}
protected virtual void InjectDependencies()
{
var context = HttpContext.Current;
if (context == null)
{
ClientScript.RegisterClientScriptBlock(this.GetType(), "context", "<script>alert('当前Http上下文为空,请与系统管理员联系!');</script>");
}
var accessor = context.ApplicationInstance as IContainerAccessor;
if (accessor == null)
{
ClientScript.RegisterClientScriptBlock(this.GetType(), "context", "<script>alert('当前应用程序实例为空,请与系统管理员联系!');</script>");
}
var container = accessor.Container;
if (container == null)
{
ClientScript.RegisterClientScriptBlock(this.GetType(), "context", "<script>alert('未找到依赖注入容器,请与系统管理员联系!');</script>");
}
container.BuildUp(this as T);
}
}
}
我们不止在页面中要调用接口,也要在UserControl中调用,那么我们就参照上面的页面基类建立一个UserControl的泛型基类。

BaseUserControl
namespace Foresee.Web
{
public abstract class BaseUserControl<T> : UserControl where T : class
{
protected override void OnInit(EventArgs e)
{
InjectDependencies();
base.OnInit(e);
}
protected virtual void InjectDependencies()
{
var context = HttpContext.Current;
if (context == null)
{
this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "context", "<script>alert('当前Http上下文为空,请与系统管理员联系!');</script>");
}
var accessor = context.ApplicationInstance as IContainerAccessor;
if (accessor == null)
{
this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "context", "<script>alert('当前应用程序实例为空,请与系统管理员联系!');</script>");
}
var container = accessor.Container;
if (container == null)
{
this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "context", "<script>alert('未找到依赖注入容器,请与系统管理员联系!');</script>");
}
container.BuildUp(this as T);
}
}
}
接下来我们建立一个UserControl文件,在里面调用查询雇员的服务接口,并绑定到ListView控件上,具体代码如下:

Code
namespace Xiaozhuang.Web
{
public partial class EmployeeList : BaseUserControl<EmployeeList>
{
#region Properties
[Dependency]
public IQueryEmployeeService instance { set; get; }
public QueryEntry queryentry { set; get; }
#endregion
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
try
{
ListView1.DataSource = instance.QueryEmployee(queryentry);
ListView1.DataBind();
}
catch
{
Response.Write("系统运行错误,请与管理员联系!");
}
}
}
}
}
这个EmployeeList继承自BaseUserControl<T>.UserControl基类,这样这个用户控件就可以实现注入了,我们只需要在属性上增加Dependency标记就可以用属性注入的方式来调用接口方法,当然你也可以通过方法注入的方式来实现。
接下来我们要用Asp.net Ajax调用这个UserControl来生成HTML,给页面上使用,我们先建立两个类ControlPage和ViewManager

Code
namespace Xiaozhuang.Web
{
public class ControlPage : Page
{
public override void VerifyRenderingInServerForm(Control control)
{
//base.VerifyRenderingInServerForm(control);
}
}
}
namespace Xiaozhuang.Web
{
/// <summary>
/// A generic user control rendering helper, basically you initialise the view manager and
/// call render to render that control, but the benifit of this version is you can access the control
/// the view manager is rendering and can set custom properties etc.
/// </summary>
/// <typeparam name="T">The type of the control you are rendering</typeparam>
public class ViewManager<T> where T : Control
{
#region Properties
private T _control = default(T);
/// <summary>
/// Gives you access to the control you are rendering allows
/// you to set custom properties etc.
/// </summary>
public T Control
{
get
{
return _control;
}
}
// Used as a placeholder page to render the control on.
private ControlPage _holder = null;
#endregion
#region Constructor
/// <summary>
/// Default constructor for this view manager, pass in the path for the control
/// that this view manager is render.
/// </summary>
/// <param name="inPath"></param>
public ViewManager(string path)
{
//Init the holder page
_holder = new ControlPage();
// Create an instance of our control
_control = (T)_holder.LoadControl(path);
// Add it to our holder page.
_holder.Controls.Add(_control);
}
#endregion
#region Rendering
/// <summary>
/// Renders the current control.
/// </summary>
/// <returns></returns>
public string Render()
{
StringWriter sw = new StringWriter();
// Execute the page capturing the output in the stringwriter.
HttpContext.Current.Server.Execute(_holder, sw, false);
// Return the output.
return sw.ToString();
}
#endregion
}
}
ControlPage类是一个简单的继承Page的类,里面重载VerifyRenderingInServerForm方法的作用是防止在UserControl生成HTML的时候如果UserControl中有服务器控件而出现的“服务器控件必须放在Form ruanat=‘server’”的错误!ViewManager类的作用是把在服务器端UserControl装在ControlPage页面中用Excute方法执行一遍并用Render方法获取到执行后输出的HTML字符串。
接下来我们到页面中去,在页面类中建立一个输出HTML的静态带WebService标记的方法,如下

Code
[WebMethod()]
public static string GetDataPage(int page, string departmentID, string EmpName, string EmpAge)
{
// Create an instance of our viewmanager.
ViewManager<EmployeeList> man = new ViewManager<EmployeeList>("~/EmployeeList.ascx");
QueryEntry queryentry = new QueryEntry();
queryentry.DepartmentID = departmentID;
queryentry.EmployeeName = EmpName;
queryentry.EmployeeAge = EmpAge;
man.Control.queryentry = queryentry;
return man.Render();
}
这个方法的作用是吧查询的参数传递给EmployeeList用户控件,通过ViewManager执行并输出HTML字符串,在Aspx页面中用Asp.Net Ajax代码来调用这个方法,并把返回的html填充到相应的Div中。如下

Code
<script type="text/javascript">
var currentPage = 0;
function LoadPage(page) {
var departmentID = document.getElementById("txtDept").value;
var empName = document.getElementById("txtName").value;
var empAge = document.getElementById("txtAge").value;
PageMethods.GetDataPage(page,departmentID,empName,empAge, function(result) {
// We loaded our data populate our div.
document.getElementById("DivContent").innerHTML = result;
},
function(error) {
alert(error.get_message());
});
}
Sys.Application.add_load(LoadPage);
</script>
至此写完,其实这个生成html的方法我用了很久了,本来这次是写架构设计的,给扯到这上面来了,也许这也算是架构设计的一部分吧。
运行效果如下:

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构