自定义服务器控件通过反射调用页面方法

  今天突然想把某一功能封装成服务器控件,但这一功能又需要连接数据库,如果直接在控件里连接数据库,那么跟在UI层直接操作数据库是一样的,也就破坏了三层架构。

  突然想到了在自定义控件里调用页面方法,但在控件里只能调用基类 System.Web.UI.Page 已声明的几个方法,比如:DataBind()。一个简单方法就是在自定义控件里调用基类已声明的方法,然后在具体页面重写此方法,达到功能的实现。这里简单介绍一下:

在自定义控件里可以这样调用

this .Page.DataBind();
在具体页面重写此方法:
     public   override   void  DataBind()
    {
        
base .DataBind();
        
// Do something 
    }
 
  但很明显我今天要介绍的不是此方法。以下进入正题。
  想用反射调用页面方法,如果有规范的方法名和参数列表,那就简单多了。这里自然想到用一接口来规范化。
  一、创建新网站(ServerControlTest)
  二、添加自定义服务器控件项目
     自定义服务器控件通过反射调用页面方法_第1张图片
  三、定义并在页面实现接口
    为了方便,直接在 Default.aspx.cs 文件中声明接口。注意:这里的接口是不包含在任何命名空间中的。
    此时Default.aspx.cs 文件中的代码如下:
using  System;
using  System.Web;
using  System.Web.UI;
using  System.Web.UI.WebControls;

public   partial   class  _Default : System.Web.UI.Page , ITestInterface
{
    
protected   void  Page_Load( object  sender, EventArgs e)
    {

    }

    
// 接口实现
     #region  TestInterface 成员
    
public   string  TestMethod( string  str)
    {
        
return   " 已调用接口:TestInterface ——  "   +  str;
    }
    
#endregion
}
// 接口定义
public   interface  ITestInterface
{
    
string  TestMethod( string  str);
}

  四、自定义控件的实现

    我们将重载控件的 OnInit 事件,在此事件中调用页面方法 TestMethod。如果此页面未实现 ITestInterface 接口,我们将抛出异常。

    控件的默认代码不变,添加以下代码:

         protected   override   void  OnInit(EventArgs e)
        {
            
base .OnInit(e);

            Type myType 
=   this .Page.GetType();
            System.Reflection.TypeFilter myFilter 
=   new  System.Reflection.TypeFilter(MyInterfaceFilter);
            
//  返回页面名称为 ITestInterface 的接口
            Type[] myInterfaces  =  myType.FindInterfaces(myFilter,  " ITestInterface " );
            
// 已实现接口
             if  (myInterfaces.Length  >   0 )
            {
                
// 我们将调用方法得到的结果赋于控件的 Text 属性
                
// 第一个参数是调用此TestMethod的对象,在这里自然是页面实例
                
// 第二个参数是方法TestMethod的参数列表,类型必须一致,无参数时可传null
                 this .Text  =  myInterfaces[ 0 ].GetMethod( " TestMethod " ).Invoke( this .Page,  new   object [] {  " 输入参数 "  }).ToString();
            }
            
// 未实现接口
             else
            {
                
throw   new  Exception( " The page doesn't implement the interface 'ITestInterface' ! " );
            }
        }
        
public   bool  MyInterfaceFilter(Type typeObj, Object criteriaObj)
        {
            
if  (typeObj.ToString()  ==  criteriaObj.ToString())
                
return   true ;
            
else
                
return   false ;
        }

  五、为项目 ServerControlTest 添加引用

  自定义服务器控件通过反射调用页面方法_第2张图片

  六、在 Default.aspx 中引用控件

<% @ Page Language = " C# "  AutoEventWireup = " true "   CodeFile = " Default.aspx.cs "  Inherits = " _Default "   %>
<% @ Register Assembly = " ServerControl "  Namespace = " ServerControl "  TagPrefix = " cc1 "   %>
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >

< html  xmlns ="http://www.w3.org/1999/xhtml" >
< head  runat ="server" >
    
< title ></ title >
</ head >
< body >
    
< form  id ="form1"  runat ="server" >
    
< div >
        
< cc1:ServerControl1  ID ="ServerControl1"  runat ="server"   />
    
</ div >
    
</ form >
</ body >
</ html >

  七、运行应用程序

    页面将输出: 已调用接口:TestInterface —— 输入参数

 

至此已介绍完毕。不过其中有些注意的地方提一下。

在查找接口时 Type[] myInterfaces = myType.FindInterfaces(myFilter, "ITestInterface"); 接口名必须是完全限定名,如果接口是存放在某一命名空间中就必须注意了。如果你觉得这样太过于局限的话,那么你可以为控件增多一个属性,用来输入接口的完全限定名。

大家如果有什么更好的方法或建议,不妨提出来,大家一起学习学习。

你可能感兴趣的:(服务器)