再說重寫IHttpHandler,實現前后端分離


aspx頁面第一次加載時,HttpHandler 里面是如何編譯指定頁面的呢?Framework提供了編譯頁面的API如下:

BuildManager.CreateInstanceFromVirtualPath(url, typeof(System.Web.UI.Page));根據虛擬路徑生成實例。

但是url頁面此時必需繼承System.Web.UI.Page,就是我們常見的ASPX頁面。但是這樣編譯時會調用aspx視圖引擎來解析aspx和對應的CodeBehind類。

對於前台純粹用JSON渲染的JS插件,解析編譯ASPX頁面似乎是多余的,aspx的生命周期也是復雜和沒什么卵用的,那問題來了,能不能只編譯類文件(當然要繼承IHttpHandler),而aspx頁面用html替換呢?

如下圖的結構,(如何一鍵建立這樣的文件結構下次再說,MVC中View和Controller分的太開了,不太習慣,中小型項目還是這樣覺的更好。)

目標:html上發送ajax請求到.cs上,並返回數據到.html

Framework提供一個方法:

var ass = BuildManager.GetCompiledAssembly(url);根據虛擬路徑得到程序集。第一次加載需要編譯慢一點,之后會很快。

url可以是這樣:/Portal/ListPageTmp.cs,即根據class文件路徑生成Assembly,

當然此時瀏覽器url是/Portal/ListPageTmp.html

我們可以在前台ajax請求時就把路徑由/Portal/ListPageTmp.html轉換成/Portal/ListPageTmp.cs,再發送ajax,也可以在后台GetHandler方法里面轉換。

我是在前台轉換的如下:(把$.ajax封裝一下,確保所有AJAX都調用此方法以便轉換url)

$.ajax({
type: 'post',
url: ‘/Portal/ListPageTmp.cs’,
async: async,
data: data,
success: function (data) { rtn = data; },
error: function (data) { rtn["result"] = "fail"; alert("操作失敗") },
dataType: 'json'
});

要想以這樣ajax請求(/Portal/ListPageTmp.cs)讓IIS接收到 那必然要改web.Config:不解釋

<system.webServer>
<handlers>
<add name="ddd" verb="*" path="*.cs" type="App.PageBase.CSHttpHandler" />
</handlers>
</system.webServer>

 

以下是IHttpHandlerFactory完整代碼:

 1  public class CSHttpHandler : IHttpHandlerFactory
 2     {
 3         public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
 4         {
 5 
 6             try
 7             {
 8                 var ass = BuildManager.GetCompiledAssembly(url);//重要的一個方法,也見過其它的跟據url生成實例的方法,但是如果不同命名空間有同名類就不好辦了。
 9                // var d = BuildManager.CreateInstanceFromVirtualPath(url, typeof(System.Web.UI.Page));
10               
11                 TypeInfo pageType = ass.DefinedTypes.Where(p => p.IsClass == true && p.BaseType.BaseType == typeof(BasePage)).FirstOrDefault();
12                 BasePage basepage = Activator.CreateInstance(pageType) as BasePage;
13                 return (IHttpHandler)basepage;
14             }
15             catch (Exception ex)
16             {
17                 throw ex;
18             }
19 
20         }
21 
22         public void ReleaseHandler(IHttpHandler handler)
23         {
24 
25 
26         }
27 
28     }

 

BasePage類,和System.Web.UI.Page類功能相當。
  1     public class BasePage : IHttpHandler
  2     {
  3 
  4      private bool _IsAjaxRequest;
  7         private string _Action;
  8         private ActionResult _ActionResult;
  9         AppCache cache = new AppCache();
 10         public BasePage()
 11         {
 12             this.IsCheckLogin = true;
 13 
 14             this.IsCheckAuth = true;
 15 
 16             _ActionResult = new ActionResult();
 17 
 18 
 19 
 20         }
 21 
 22         public bool IsReusable { get; set; }
 23         protected HttpRequest Request
 24         {
 25             get;
 26             set;
 27         }
 28         protected HttpResponse Response
 29         {
 30             get;
 31             set;
 32         }
 33 
 34         public virtual void ProcessRequest(HttpContext context)
 35         {
 36             this.Request = context.Request;
 37             this.Response = context.Response;
 38             this.OnInit();
 39 
 40         }
 41         protected string Action
 42         {
 43             get
 44             {
 45                 return _Action;
 46             }
 47 
 48 
 49         }
//判斷是否AJAX請求,這種模式,到這里的請求都是AJAX請求,因為HTML加載時不用觸發請求到后端的。
50 protected bool IsAjaxRequest 51 { 52 get 53 { 54 return _IsAjaxRequest; 55 } 56 57 58 } 59 protected virtual void OnInit() 60 { 61 _IsAjaxRequest = this.Request.Headers["X-Requested-With"] == "XMLHttpRequest" ? true : false; 62 _Action = Request.QueryString["Action"] == null ? "" : Request.QueryString["Action"].ToString(); 63 form = new FormData(Request.Form);
//根據URL上的Action參數找到繼承此類上的方法,並反射調用。

MethodInfo method = this.GetType().GetMethod(Action);
if (method == null)
{
throw new Exception("找不到【" + method.Name + "】方法.");
}
else
{
try
{

//綁定參數並調用,當然調用前也可以也可以做ActionFilter檢查
InvokMethod(this, method);

 
         

}
catch (Exception ex)
{
 actionResut.hasError = true;
 actionResut.message = ex.InnerException.Message;
}

 
         

}

//返回json數據
ReturnData(actionResut);


64 }
//綁定Action方法的參數。
65 protected object InvokMethod(object ins, MethodInfo method) 66 { 67 68 69 var methodParam = method.GetParameters(); 70 object[] param = new object[methodParam.Length]; 71 for (int i = 0; i < methodParam.Length; i++) 72 { 73 string name = methodParam[i].Name; 74 Type paramType = methodParam[i].ParameterType; 75 if (paramType.IsGenericType) paramType = paramType.GetGenericArguments()[0]; 76 string ArgValue = Request.QueryString[name]; 77 string FormValue = Request.Form[name]; 78 string value = string.IsNullOrEmpty(ArgValue) ? FormValue : ArgValue; 79 if (!string.IsNullOrEmpty(value)) 80 { 81 if (paramType.IsValueType) 82 { 83 param[i] = Convert.ChangeType(value, paramType); 84 } 85 else if (paramType == typeof(string)) 86 { 87 param[i] = value; 88 } 89 else 90 { 91 param[i] = JsonHelper.Json2Object(value.ToString(), paramType); 92 } 93 } 94 95 else 96 { 97 param[i] = null; 98 } 99 } 100 return method.Invoke(ins, param); 101 102 } 103 }

 

ListPageTmp.html對應的類文件是這樣的:
如果有ListPageTmp.html?Action=Test&Id=1&name=zhangsan的ajax請求,會根據名稱找到ListPageTmp.cs,實例化后將url參數綁定到Test方法參數上執行,返回JSON.
 
 1     public partial class ListPageTmp :BasePage
 2     { 
 3     
[Auth(Role="Admin")]//反射調用前也可檢查是否有attribute並做 攔截 ,類似MVC的ActionFilter. 4 public void Test(int Id,string name) 5 { 6 7 actionResut.Add("Name",name);
               actionResut.Add("Id",Id);
 8            
 9         }
10 
11   
12     
13     }

 

這樣前后端就分開了。html加載完成后,根據不同需要發送ajax從服務端取json數據綁定的前台。

也實現了MVC里面的一些功能,如ActionFilter,Action參數綁定,ActionResult和MVC的不太一樣。沒有很復雜的ActionResult,只是封裝json.

MVC是通過URL 路由 找到 Control和Action,由Action定向到View,

今天說的這個方案,是通過View找到Control和Action 執行后返回JSON給View.

 

唉,不知道說明白了沒有。。。。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM