在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
跟 ASP.NET MVC 与 Web API 比起来,在 Web Forms 应用程式中使用 Dependency Injection 要来的麻烦些。这里用一个范例来说明如何注入相依物件至 Web Forms 的 ASPX 页面。 使用的开发工具与类别库:
基于测试或其他原因,希望 ASPX 网页只依赖特定服务的介面,而不要依赖具象类别。 假设首页 Default.aspx 需要一个传回“Hello World!”字串的服务,而我们将此服务的介面命名为 IHelloService。以下为此服务的介面与实作类别: public interface IHelloService { string Hello(string name); } public class HelloService : IHelloService { public string Hello(string name) { return "Hello, " + name; } }
Default.aspx 的 code-behind 类别大概会像这样: public partial class Default : System.Web.UI.Page { public IHelloService HelloService { get; set; } protected void Page_Load(object sender, EventArgs e) { // 在網頁上輸出一段字串訊息。訊息內容由 HelloService 提供。 Response.Write(this.HelloService.Hello("DI in ASP.NET Web Forms!")); } }
问题来了:Page 物件是由 ASP.NET Web Forms 框架所建立的,我们如何从外界动态注入 IHelloService 物件呢?
public partial class Default : System.Web.UI.Page { public IHelloService HelloService { get; set; } public Default() { // 透过一个共用的 Container 物件来解析相依物件。 this.HelloService = AppShared.Container.Resolve<IHelloService>(); } protected void Page_Load(object sender, EventArgs e) { // 在网页上输出一段字串讯息。讯息内容由 HelloService 提供。 Response.Write(this.HelloService.Hello("DI in ASP.NET Web Forms!")); } }
此解法的一个问题是,你必须在每一个 ASPX 页面的 code-behind 类别中引用 DI 容器的命名空间,而这样就变成到处都依赖特定的 DI 容器了。我们希望尽可能把呼叫 DI 容器的程式码集中写在少数几个地方就好。
建立一个新的 ASP.NET Web Application 专案,目标平台选择 .NET Framework 4.5,专案名称命名为:WebFormsDemo。 专案范本选择 Empty,然后在 Add folder and core references for 项目上勾选“Web Forms”。 专案建立完成后,透过 NuGet 管理员加入 Unity 套件。
public class Global : System.Web.HttpApplication { protected void Application_Start(object sender, EventArgs e) { var container = new UnityContainer(); Application["Container"] = container; // 把容器物件保存在共用變數裡 // 註冊型別 container.RegisterType<IHelloService, HelloService>(); } }
Step 3:撰寫 HTTP Handler
public class UnityPageHandlerFactory : System.Web.UI.PageHandlerFactory { public override IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path) { Page page = base.GetHandler(context, requestType, virtualPath, path) as Page; if (page != null) { var container = context.Application["Container"] as IUnityContainer; var properties = GetInjectableProperties(page.GetType()); foreach (var prop in properties) { try { var service = container.Resolve(prop.PropertyType); if (service != null) { prop.SetValue(page, service); } } catch { // 沒辦法解析型別就算了。 } } } return page; } public static PropertyInfo[] GetInjectableProperties(Type type) { var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); if (props.Length == 0) { // 傳入的型別若是由 ASPX 頁面所生成的類別,那就必須取得其父類別(code-behind 類別)的屬性。 props = type.BaseType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); } return props; } } 程式說明:
<configuration> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> </system.web> <system.webServer> <handlers> <add name="UnityPageHandlerFactory" path="*.aspx" verb="*" type="WebFormsDemo.Infrastructure.UnityPageHandlerFactory"/> </handlers> </system.webServer> </configuration>
基础建设的部分到此步骤已经完成,接着就是撰写各个 ASPX 页面。 public partial class Default : System.Web.UI.Page { public IHelloService HelloService { get; set; } protected void Page_Load(object sender, EventArgs e) { // 在網頁上輸出一段字串訊息。訊息內容由 HelloService 提供。 Response.Write(this.HelloService.Hello("DI in ASP.NET Web Forms!")); } }
你可以看到,ASPX 网页并不需要引用 Unity 容器的命名空间,因为注入相依物件的动作已经由基础建设预先帮你处理好了。
|
请发表评论