由於.net MVC 的controller 依賴於HttpContext,而我們在上一篇中的沙箱模式已經把一次http請求轉換為反射調用,並且http上下文不支持跨域,所以我們要重造一個controller。
我們在寫mvc項目的時候經常會用到ViewBag、ViewData,那我們就先聲明這兩個變量:
public dynamic ViewBag = new DynamicViewBag(); public ViewDataDictionary ViewData = new ViewDataDictionary();
當然還可以根據自己的需要構建更多的特性。
我們在一個網絡請求中避免不了會攜帶一些參數,那這些參數該如何傳到沙箱中呢?我們定義了一個RefRequestEntity類,他負責對我們的參數經行打包,把參數打包后對象作為參數傳到沙箱內部:
/// <summary>用戶的請求信息
/// </summary>
[Serializable]
public class RefRequestEntity
{
/// <summary>當前用戶在本頁面具備的所有權限
/// </summary>
public List<RightEntity> PageRights;
/// <summary>用戶請求攜帶的所有參數
/// </summary>
public HuberRequest<string, object> Request;
/// <summary>
/// 用戶id
/// </summary>
public string UserID { get; set; }
public RefRequestEntity()
{
PageRights = new List<RightEntity>();
Request = new HuberRequest<string, object>();
}
}
在.net mvc中我們可以返回ActionResult,在ActionResult內部調用時才會做出真正的Response(更多細節請參考mvc實現原理),當然它在執行的整個過程中都是由HttpContext貫穿的,我們沒有了HttpContext,我們就只自己構造一些Response方法。
返回View()結果:
mvc中由ViewEngine來編譯執行我們寫好的視圖文件(.aspx、.cshtml),而我們則借助於RazorEngine來編譯執行razor視圖文件,它可以支持我們常用的ViewBag、using、layout等(更多請見RazorEngine)。在本篇中我們還是把精力放回controller的實現中,關於視圖的實現我們在下一篇中在講。我們先看一下一個View的簡單實現:
/// <summary>返回試圖的執行結果
/// </summary>
/// <returns></returns>
protected string View()
{
var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Global);//getActionPath:獲取action對應的視圖文件key值。
return new CompileView().RunCompile(tKey, null, null, ViewBag); //返回執行結果
}
View()的執行結果是一段html代碼。這樣我們在請求一個action的時候,就可以正常的呈現一個頁面了。下邊是一個Controller基類的實現,它完成了View、PartialView的實現Demo:
public class HuberController
{
public dynamic ViewBag = new DynamicViewBag();
public ViewDataDictionary ViewData = new ViewDataDictionary();
/// <summary>設置ViewBag的值
/// </summary>
/// <param name="key">鍵</param>
/// <param name="value">值</param>
internal void AddViewBageValues(string key, object value)
{
Impromptu.InvokeSet(ViewBag, key, value);
}
/// <summary>返回試圖的執行結果
/// </summary>
/// <returns></returns>
protected string View()
{
var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Global);
return new CompileView().RunCompile(tKey, null, null, ViewBag);
}
/// <summary>返回試圖的執行結果
/// </summary>
/// <typeparam name="T">model的類型</typeparam>
/// <param name="model">model</param>
/// <returns></returns>
protected string View<T>(T model)
{
var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Global);
return new CompileView().RunCompile(tKey, typeof(T), model, ViewBag);
}
/// <summary>返回試圖的執行結果
/// </summary>
/// <param name="viewName">視圖的全路徑(相對於運行目錄的全路徑)</param>
/// <returns></returns>
protected string View(string viewName)
{
var tKey = Engine.Razor.GetKey(getActionPathWith(viewName), ResolveType.Global);
return new CompileView().RunCompile(tKey, null, null, ViewBag);
}
/// <summary>返回試圖的執行結果
/// </summary>
/// <typeparam name="T">model的類型</typeparam>
/// <param name="viewName">視圖的全路徑(相對於運行目錄的全路徑)</param>
/// <param name="model">model</param>
/// <returns></returns>
protected string View<T>(string viewName, T model)
{
var tKey = Engine.Razor.GetKey(getActionPathWith(viewName), ResolveType.Global);
return new CompileView().RunCompile(tKey, typeof(T), model, ViewBag);
}
/// <summary>返回局部試圖的執行結果
/// </summary>
/// <returns></returns>
protected string PartialView()
{
var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Include);
return new CompileView().RunCompile(tKey, null, null, ViewBag);
}
/// <summary>返回局部試圖的執行結果
/// </summary>
/// <typeparam name="T">model的類型</typeparam>
/// <param name="model">model</param>
/// <returns></returns>
protected string PartialView<T>(T model)
{
var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Include);
return new CompileView().RunCompile(tKey, typeof(T), model, ViewBag);
}
/// <summary>返回局部試圖的執行結果
/// </summary>
/// <param name="viewName">視圖的全路徑(相對於運行目錄的全路徑)</param>
/// <returns></returns>
protected string PartialView(string viewName)
{
var tKey = Engine.Razor.GetKey(getActionPathWith(viewName), ResolveType.Include);
return new CompileView().RunCompile(tKey, null, null, ViewBag);
}
/// <summary>返回局部試圖的執行結果
/// </summary>
/// <typeparam name="T">model的類型</typeparam>
/// <param name="viewName">視圖的全路徑(相對於運行目錄的全路徑)</param>
/// <param name="model">model</param>
/// <returns></returns>
protected string PartialView<T>(string viewName, T model)
{
var tKey = Engine.Razor.GetKey(getActionPathWith(viewName), ResolveType.Include);
return new CompileView().RunCompile(tKey, typeof(T), model, ViewBag);
}
/// <summary>獲取action對應view的物理文件地址
/// </summary>
/// <returns></returns>
private string getActionPath()
{
string key = string.Empty;
StackTrace trace = new StackTrace();
MethodBase methodName = trace.GetFrame(2).GetMethod();
string className = methodName.ReflectedType.FullName;
string assName = HuberHttpModule.CurDomainAssemblyName;
key = className.Substring(assName.Length);
key = key.Replace(".Controllers.", ".Views.");
key = key.Substring(0, key.Length - 10);
key = key.Replace(".", "\\");
key += "\\" + methodName.Name + ".cshtml";
return key;
}
/// <summary>根據action名獲取其對應view的物理文件地址
/// </summary>
/// <param name="ActionName">action名(同一controller中)</param>
/// <returns></returns>
private string getActionPathWith(string ActionName)
{
string key = string.Empty;
StackTrace trace = new StackTrace();
MethodBase methodName = trace.GetFrame(2).GetMethod();
string className = methodName.ReflectedType.FullName;
string assName = HuberHttpModule.CurDomainAssemblyName;
key = className.Substring(assName.Length);
key = key.Replace(".Controllers.", ".Views.");
key = key.Substring(0, key.Length - 10);
key = key.Replace(".", "\\");
key += "\\" + ActionName + ".cshtml";
return key;
}
}
我們上邊列出了對Razor編譯執行的簡單過程,還是那句話,RazorEngine的更多實現細節將在下一篇講解。那么現在問題來了,我們得到了html代碼或者說我們執行玩自己的業務邏輯以后如何把這個結果輸出呢(即HttpResponse)?
我們定義了一個RefRespondEntity類,它來承載返回結果,並把結果返回到沙箱外層的調用者,再由這個調用者將這個RefRespondEntity對象Response出去:
[Serializable]
public class RefRespondEntity
{
public RefRespondEntity(RespondType type)
{
ResultType = type;
}
/// <summary>返回結果的數據類型
/// </summary>
public RespondType ResultType { get; set; }
/// <summary>返回結果的內容
/// 如果是ResultType=_Redirect那么ResultContext=301
/// 如果是ResultType=_Stream那么ResultContext="文件名.zip",當然這個文件名可以隨意定義
/// </summary>
public object ResultContext { get; set; }
/// <summary>返回結果的文件流
/// </summary>
public byte[] ResultStream { get; set; }
}
//一個action的demo
public RefRespondEntity Index4(RefRequestEntity param)
{
object AA = param.Request["A"];
object BB = param.Request["B"];
object CC = param.Request["C"];
RefRespondEntity result = new RefRespondEntity(RespondType._String);
result.ResultContext = View();
object tt = ViewBag.test;
return result;
}
var result = sandBox.InvokeMothod(urlEntity.controller, urlEntity.action, paras);//sandBox是一個沙箱的實例化對象
RequestHandle.ResposeResult(respond, result);//輸出結果
/// <summary>響應工具類
/// </summary>
public class RequestHandle
{
private static bool IsAjax(HttpRequest request)
{
return request.Headers["X-Requested-With"] != null;
}
/// <summary>將reques請求的參數封裝到CorRefEntity對象中
/// </summary>
/// <param name="para"></param>
/// <param name="request"></param>
public static void FillCorRefEntity(RefRequestEntity para, HttpRequest request)
{
foreach (var key in request.Params.AllKeys)
{
para.Request.Add(key, request.Params[key]);
}
}
/// <summary>URL404
/// </summary>
/// <param name="request"></param>
/// <param name="respond"></param>
public static void ResponseNotfound(HttpRequest request, HttpResponse respond)
{
if (IsAjax(request))
{
respond.Write(ResponseCodeEntity.CODE404);
respond.End();
}
else
{
respond.Redirect(ResponseCodeEntity.ULR404);
respond.End();
}
}
/// <summary>NoLogin
/// </summary>
/// <param name="request"></param>
/// <param name="respond"></param>
public static void ResponseNoLogin(HttpRequest request, HttpResponse respond)
{
if (IsAjax(request))
{
respond.Write(ResponseCodeEntity.NoLogin);
respond.End();
}
else
{
respond.Redirect(ResponseCodeEntity.LoginURL);//需要改成非調轉形式
respond.End();
}
}
/// <summary>NoRight
/// </summary>
/// <param name="request"></param>
/// <param name="respond"></param>
public static void ResponseNoRight(HttpRequest request, HttpResponse respond)
{
if (IsAjax(request))
{
respond.Write(ResponseCodeEntity.NoRight);
respond.End();
}
else
{
respond.Redirect(ResponseCodeEntity.NoRightURL);//需要改成非調轉形式
respond.End();
}
}
public static void ResposeResult(HttpResponse respond, object result)
{
if (typeof(RefRespondEntity) == result.GetType())
{
RefRespondEntity temp_result = (RefRespondEntity)result;
if (temp_result.ResultType == RespondType._Redirect)
{
respond.Redirect((string)temp_result.ResultContext);
respond.End();
}
else if (temp_result.ResultType == RespondType._Stream)
{
byte[] st = (byte[])temp_result.ResultStream;
respond.ContentType = "application/octet-stream";
respond.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", (string)temp_result.ResultContext));
respond.OutputStream.Write(st, 0, st.Length);
respond.End();
}
else
{
respond.Write(temp_result.ResultContext);
respond.End();
}
}
else
{
respond.Write("Huber Module respose is not a RefRespondEntity");
}
}
}
public class ResponseCodeEntity
{
/// <summary>404
/// </summary>
public static string ULR404 = "/NotPageFound/_404";
/// <summary>404ajax
/// </summary>
public static string CODE404 = "NotPage";
/// <summary>登錄頁URL
/// </summary>
public static string LoginURL = "/User/Login";
/// <summary>未登錄ajax
/// </summary>
public static string NoLogin = "NoLogin";
/// <summary>沒有權限ajax
/// </summary>
public static string NoRight = "NoRight";
/// <summary>沒有權限url
/// </summary>
public static string NoRightURL = "/User/NoRight";
}
轉載請注明出處:http://www.cnblogs.com/eric-z/p/5047172.html
第四篇 基於.net搭建熱插拔式web框架(RazorEngine實現)
