基于.Net3.5 Nhibernate 整合 Extjs 框架设计

转载注明出处

http://blog.csdn.net/xugangjava/article/details/14121801

现有项目都是基于.Net3.5的,后台以前项目全部使用的Nhibernate。Extjs前台 主要和后台ashx文件交互。

自己设计了一套简单的MVC框架,设计一个RouteHandler 类 实现 IHttpHandler IRequiresSessionState来实现路由功能。主要实现一个ashx可以实现多个方法。

为了提高性能IResuserable 返回true,所以必须进行同步处理,将HttpContext封装到一个对象里面(SyncContext后面给出),在Handler初始化的时候

会反射一次读取该类含有[Ajax]属性的方法信息保存到一个Map里面,根据页面请求的参数来执行不同的方法。

//实现方法路由功能,ashx基类 
public abstract class RouteHandler : IHttpHandler, IRequiresSessionState
{
	#region IHttpHandler 成员
	//这里返回true,所以需要对登录用户的相关变量进行同步处理
	public bool IsReusable { get { return true; } }

	//类方法信息对象
	public class HandlerInfo
	{
		public MethodInfo mehtod { private set; get; }
		public AjaxAttribute attr { private set; get; }
		public int paramLen { private set; get; }
		public List paramInfos { private set; get; }

		public HandlerInfo(MethodInfo mehtod, AjaxAttribute attr)
		{
			this.mehtod = mehtod;
			paramInfos = mehtod.GetParameters().ToList();
			paramLen = paramInfos.Count;
			this.attr = attr;
		}
	}

	protected static NLog.Logger Log
	{
		get { return NLog.LogManager.GetCurrentClassLogger(); }
	}

	private readonly IDictionary _routes;
	
	//初始化的时候进行反射,将方法名 ,方法信息保存到一个map里面
	//页面调用的时候,前台直接给出参数 /url?f=methodName 来调用相关方法
	protected RouteHandler()
	{
		_routes = new Dictionary();
		var type = GetType();
		var methods = type.GetMethods();
		foreach (var m in methods)
		{
			var attributes = m.GetCustomAttributes(false);
			var ajax = (AjaxAttribute)attributes.SingleOrDefault(x => x is AjaxAttribute);
			if (ajax == null) continue;
			_routes[m.Name] = new HandlerInfo(m, ajax);
		}
	}

        //为了快速开放,如果调试状态下,前台将直接弹出 错误对话框
	public void Debug(string message, HttpContext context)
	{
#if DEBUG
		context.Response.ContentType = "text/html";
		context.Response.Write("TRACE:" + message);
#endif
	}
	//这里其实就是一个模版模式了,直接查找 参数 f来 
	//调用不同的方法,Extjs前台数据 Ext.endcode 可以转换为不同的json对象
	//或者基本对象,来调用函数,为了提高性能,所以只在类初始化的时候 反射一次
	public void ProcessRequest(HttpContext context)
	{
		context.Response.ContentType = "application/json";
		SyncContext syncContext = null;
		try
		{
			var function = context.Request["f"];
			var type = GetType();
			if (null == function || !_routes.ContainsKey(function))
			{
				Debug(type.Name + "方法" + function + "未找到!", context);
				return;
			}
			var handler = _routes[function];
			var ajax = handler.attr;
			var method = handler.mehtod;
			var paramLen = handler.paramLen;
			if (handler.attr.Login && context.Session[ConstKey.UserModle] == null)
			{
				Debug(type.Name + "方法" + function + "需要登录", context);
				context.Response.StatusCode = 905;
				return;
			}
			if (handler.attr.Login)
			{
				var user = (Users)context.Session[ConstKey.UserModle];
				var noLoging = user == null;
				var isMachine = !noLoging && user.IsMachineBind==-1 ;//&& cmpLevle!=0;
					  
				if (noLoging)
				{
					Debug("您无权访问该页面,需要登录", context);
					return;
				}
				//todo other limits
			}
			var mParams = method.GetParameters();
			var paramArray = new object[paramLen];

			foreach (var mParamInfo in mParams)
			{
				if (mParamInfo.ParameterType == typeof(SyncContext))
				{
					syncContext = new SyncContext(context);
					paramArray[mParamInfo.Position] = syncContext;
					continue;
				}
				var value = context.Request[mParamInfo.Name];
				if (value == null)
				{
					Debug(type.Name + "方法" + method.Name + "参数" + mParamInfo.Name + "缺失", context);
					return;
				}
				if (mParamInfo.ParameterType == typeof(int))
				{
					paramArray[mParamInfo.Position] = int.Parse(value);
				}
				else if (mParamInfo.ParameterType == typeof(bool))
				{
					paramArray[mParamInfo.Position] = bool.Parse(value);
				}
				else if (mParamInfo.ParameterType == typeof(JArray) ||
					mParamInfo.ParameterType == typeof(JObject))
				{
					paramArray[mParamInfo.Position] = JsonConvert.DeserializeObject(value);
				}
				else
				{
					paramArray[mParamInfo.Position] = value;
				}
			}

			if (method.ReturnType != typeof(void))
			{
				context.Response.Write(JsonConvert.SerializeObject(method.Invoke(this, paramArray)));
			}
			else
			{
				method.Invoke(this, paramArray);
			}
		}
		catch (Exception ex)
		{
			Log.Error(ex + ex.Message);
			Debug(ex + ex.Message, context);
		}
		finally
		{
			if (syncContext != null) syncContext.Dispose();
			context.Response.Flush();
		 //   context.Response.End();
		}
	}
	#endregion


}
	
//方法属性信息,含有该属性的方法均可为前台调用
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class AjaxAttribute : Attribute
{
	public bool Login { get; set; }
	public int[] Auth { get; set; }
}


//实现用户信相关变量的同步,前面IReuseable是true的,所以相关信息全部保存到该类里面
//来实现同步功能,Nhibernate的 ISession是非线程安全的,所以也与该类进行绑定
//SyncContext 包装HttpContext  通过HttpContext 来绑定ISession
public sealed class SyncContext :IDisposable
{
	private readonly HttpContext _context;
	public HttpContext Context { get { return _context; } }
	public HttpSessionState Session { get { return _context.Session; } }
	public HttpRequest Request { get { return _context.Request; } }
	public HttpResponse Response { get { return _context.Response; } }
	public HttpServerUtility Server { get { return _context.Server; } }
	public Cache Cache { get { return _context.Cache; } }
	public ISession NSession { get { return DocSessionFactory.CurrentSession(_context); } }
	private ITransaction _nTransactionTran;
	
	//事物支持
	public ITransaction NBeginTransactionTran()
	{
		return _nTransactionTran ?? (_nTransactionTran = NSession.BeginTransaction());
	}
	
	//关闭的时候 释放 ISession
	public void Dispose()
	{
		if (_nTransactionTran != null && !_nTransactionTran.WasCommitted)
		{
			_nTransactionTran.Rollback();
		}
		if (NSession.IsConnected) NSession.Disconnect();
	}

	//用户登录对象
	public Users UserModel
	{
		get
		{
			return (Users)Session[ConstKey.UserModle];
		}
		set
		{
			Session[ConstKey.UserModle] = value;
		}
	}

	public SyncContext(HttpContext context)
	{
		_context = context;
	}

	public string LoadParam(string key)
	{
		if (Request[key] == null) throw new Exception("以无效参数非法访问页面");
		return Request[key];
	}

	public IDictionary LoadParam(params string[] param)
	{
		var d = new Dictionary();
		foreach (var s in param)
		{
			if (Request[s] == null) throw new Exception("以无效参数非法访问页面");
			d[s] = Request[s];
		}
		return d;
	}



	public bool TryLoadParam(string key, out string value)
	{
		value = string.Empty;
		if (Request[key] == null) return false;
		value = Request[key];
		return true;
	}

	public object LoadSessionKey(string key)
	{
		var o = Session[key];
		if (o == null)
			throw new Exception("获取 Session中的" + key + "缺失!");
		return o;
	}

	public void DropSessionKey(params string[] param)
	{
		foreach (var s in param.Where(s => Session[s] != null))
		{
			Session.Remove(s);
		}
	}

	/// 
	/// 判断是否只有否一用户登录的权限
	/// 
	public bool VaildateRole(params short[] roles)
	{
		return roles.Any(r => UserModel.Role == r);
	}

}





这样一个简单高效的MVC框架就完成了,没有复杂的配置,一切追求简单高效。

下面是项目中基于该框架的调用示例。查询列表显示使用通用存储过程来实现效率最高。保存 修改则使用Nhibernate 简单明了。这里的参数只有int 和String,前台使用Ext.encode 后台会自动将其转换为JObject JArray,第一个方法是最常见的分页查询,第二个是业务处理方法

public class DocFileInfoHandler : RouteHandler
{
	[Ajax(Login = true)]
	public JObject QuerySelfFolder(int node, int start, int limit, SyncContext syncContext)
	{
		var id = node;
		var dao = new DocFolderDao(syncContext.NSession);
		var p = JPage.Load(start, limit);
		p.columsForSelect = @"ID,
				Name,
				ISize,
				SName,
				LastModifyTime,
				CurVersion,
				SLogo,
				LockerFullName,
				IsDir,
				FtpPath,
				LockerId";
		p.orderBy = "IsDir desc,CreateTime desc";
		p.fromWhere = "DocumentFolderView";
		p.condition = " FolderID= " + id + " AND [Status]=1 ";
		DoMachineLimit(ref p.condition, syncContext.UserModel);

		return dao.JPageProc(p);
	}

 

	[Ajax(Login = true)]
	public JObject FileRename(int fileid, bool isDir, string newName, SyncContext syncContext)
	{
		var session = syncContext.NSession;
		if (isDir)
		{
			var folder = session.Get(fileid);
			if (folder == null)
			{
				return CallBack("文件夹不存在!");
			}
			var fdao = new DocFolderDao(session);

			if (fdao.IsExistsSelfFolder(folder.ParentDirID, newName))
			{
				return CallBack("该文件夹下或回收站中,已经存在名为" + newName + "的文件夹了!");
			}
			folder.DirName = newName;
			session.Update(folder);
			session.Flush();
		}
		else
		{
			var file = session.Get(fileid);
			if (file == null)
			{
				return CallBack("文件不存在!");
			}
			var ne = RawNameExt(file.FileName);
			var newFileName = newName + "." + ne.Ext;
			var fdao = new DocFileInfoDao(session);
			if (fdao.IsExistsFileName(file.FolderId, newFileName))
			{
				return CallBack("该文件夹下或回收站中,已经存在名为" + newName + "的文件了!");
			}
			file.FileName = newFileName;
			session.Update(file);
			session.Flush();
		}
		return OK;
	}

}

前台调用

var f = new XG.Form.SimpelPoupForm({
                    title: title,
                    url: '/logic/DocFileInfoHandler.ashx?f=FileRename',
                    width: 350,
                    height: 150,
                    items: [{
                        fieldLabel: label,
                        width: 200,
                        emptyText: json.IsDir ? '文件夹名称' : '文件名,不包括扩展名',
                        name: 'newName'
                    }, {
                        name: 'fileid',
                        value: json.ID,
                        xtype: 'hidden'
                    }, {
                        name: 'isDir',
                        value: isDir,
                        xtype: 'hidden'
                    }],
                    before_submit: beforeSubmit,
                    success: function (action) {
                        var msg = f.getMessage(action);
                        if (msg === "OK") {
                            grid.getStore().reload();
                        }
                    }
                });
                f.show(this);

这里是我封装的一个弹出表单,/logic/DocFileInfoHandler.ashx?f=FileRename 就表示调用DocFileInfoHandler.ashx 的FileRename 方法。 name: 'newName',name: 'fileid', name: 'isDir',就自动对应后台的方法的三个变量名称。

这样就节省了大量的重复,繁杂的权限验证,参数传递,关闭数据库连接等容易遗漏出错的重复相关代码。

文中的代码只是为了阐述大概思路,所以相关类没有全部给出。

如有不对的地方,欢迎指正。







你可能感兴趣的:(C#)