十五、EnterpriseFrameWork框架核心类库之系统启动入口与初始化
本章内容是讲三种开发模式,web模式、Winform模式和Wcf模式的系统启动入口有什么区别,以及启动后系统初始化的内容;为什么要把这些单独提出来讲一章,因为我觉得本章非常重要,我们都知道程序中的main()函数,称之为主函数,是所有程序运行的入口;当你拿着一个程序肯定是从这个函数开始阅读,慢慢的深入了解整个程序的运行流程;而光看那些功能代码块是掌握不了系统运行时的一些机制的;
只有掌握本章的内容后,那么在以后项目中遇到的问题基本上都能直接定位,并找到产生的原因,不然你会觉得所有产生的问题都莫名其妙,不知道从哪里下手调试;项目中的配置文件也是在系统初始化中使用的,要了解配置的值到底有什么作用也必须搞清楚系统初始化的过程,还有就是框架中的很多设计思想就是基于此处产生的,最典型的就是控制器的设计,为什么控制器要如此设计,看完后应该会深有体会;
接下来我就分别对框架中的几种模式的系统启动入口进行讲解:
1.Web版系统启动入口
2.Winform版系统启动入口
3.Wcf版系统启动入口
4.启动后初始化内容
源代码目录结构:
一、Web版系统启动入口
Web版是三层结构程序,但跟wcf版又不一样,分为浏览器、Web服务器和数据库,所有代码都是部署在Web服务器上的,Windows下的常用web服务器就是IIS了;Net下的web系统启动入口通常都是使用Global.asax文件;是可以把初始化代码AppGlobal放在此文件中,但是框架为什么没有这么做,因为开始的设计就是在EFWWeb项目中是不能写任何cs代码的,想想看如果EFWWeb项目没有cs代码,那么就只有html代码和javascript代码,这样EFWWeb项目就不需要编译,要编译的代码都放在逻辑层项目中,我们发布就变得非常方便,只需拷贝更新逻辑层项目的dll和EFWWeb项目的aspx文件和js文件;如果只修改了界面那编译都不用了;
那么启动入口不在Global.asax文件中那又在哪了,框架利用了httpModules来实现;先看AppGlobalHttpModule对象的代码,继承net框架中的IHttpModule接口,在实现的Init方法中通过context.BeginRequest事件调用了AppGlobal.AppStart方法实现系统初始化;
/// <summary>
/// web系统启动调用此对象
/// </summary>
public class AppGlobalHttpModule : IHttpModule
{ #region IHttpModule 成员 public void Dispose()
{
AppGlobal.AppEnd();
}
private HttpApplication _context;
public void Init(HttpApplication context)
{
_context = context;
context.BeginRequest += new EventHandler(context_BeginRequest);
} void context_BeginRequest(object sender, EventArgs e)
{
AppGlobal.AppRootPath = _context.Server.MapPath("~/");
AppGlobal.AppStart(AppGlobalType.Web);
} #endregion
}
在Web.config配置文件中需要对AppGlobalHttpModule 对象进行配置;
Web版系统就是利用httpModules来实现的,再讨论一下页面想后台控制器进行Http请求的的流程;如下图,界面javascript代码利用jquery中的Ajax功能向Web服务器发送请求,Url地址指定控制器的名称和控制器方法名称;
Web服务器利用httpHandlers来接收前端的所有请求,看一下APIHttpHandler的代码,继承net框架中的IHttpHandler接口,在实现接口的ProcessRequest方法中根据url中的控制器名称和方法名称,利用反射机制创建Web控制器,并执行控制器中的方法返回结果输出到页面;
/// <summary>
/// Http请求处理对象
/// </summary>
public class APIHttpHandler : IHttpHandler, IRequiresSessionState
{
/// <summary>
/// 您将需要在您网站的 web.config 文件中配置此处理程序,
/// 并向 IIS 注册此处理程序,然后才能进行使用。有关详细信息,
/// 请参见下面的链接: http://go.microsoft.com/?linkid=8101007
/// </summary>
#region IHttpHandler Members public void ProcessRequest(HttpContext context)
{ try
{
if (AppGlobal.IsRun == false) throw new Exception("系统未正常启动!");
string sController = context.Request["controller"].ToString().Trim();
string sMothod = context.Request["method"].ToString().Trim(); if (!String.IsNullOrEmpty(sController) && !String.IsNullOrEmpty(sMothod))
{ CmdInvoke(context, sController, sMothod);
}
else
{
context.Response.Write("error");//命令错误
}
}
catch (Exception err)
{
context.Response.Write("exception");//执行异常
//记录错误日志
ZhyContainer.CreateException().HandleException(err, "HISPolicy");
}
finally
{
context.Response.End();
}
} public bool IsReusable
{
get
{
return false;
}
} #endregion private void CmdInvoke(HttpContext context, string sController, string sMothod)
{
List<Cmd_Controller> cmd = (List<Cmd_Controller>)AppGlobal.cache.GetData("cmdWebController"); Cmd_Controller cmdC = cmd.Find(x => x.controllerName == sController);
if (cmdC != null)
{
Cmd_Method cmdM= cmdC.cmdMethod.Find(x => x.methodName == sMothod);
if (cmdM != null)
{
if (System.Configuration.ConfigurationManager.AppSettings["TurnOnLoginRight"] == "true" && cmdC.webController.GetSysLoginRight.UserId == )
{
context.Response.Write("nologin");//没登陆
}
else
{
//每次请求控制器必须创建一个新的数据库链接
//if (cmdC.webController.GetDb() == null)
//{
EFWCoreLib.CoreFrame.DbProvider.AbstractDatabase Rdb = EFWCoreLib.CoreFrame.DbProvider.FactoryDatabase.GetDatabase();
Rdb.WorkId = cmdC.webController.GetSysLoginRight.WorkId;
//创建数据库连接
cmdC.webController.BindDb(Rdb, AppGlobal.container); if (cmdM.dbkeys != null && cmdM.dbkeys.Count > )
{
cmdC.webController.BindMoreDb(Rdb, "default");
foreach (string dbkey in cmdM.dbkeys)
{
EFWCoreLib.CoreFrame.DbProvider.AbstractDatabase _Rdb = EFWCoreLib.CoreFrame.DbProvider.FactoryDatabase.GetDatabase(dbkey);
_Rdb.WorkId = cmdC.webController.GetSysLoginRight.WorkId;
//创建数据库连接
cmdC.webController.BindMoreDb(_Rdb,dbkey);
}
} //}
BeginInvoke(context, cmdC.webController);
cmdM.methodInfo.Invoke(cmdC.webController, null);
EndInvoke(context, cmdC.webController);
}
}
else
{
context.Response.Write("error");//命令错误
}
}
else
{
context.Response.Write("error");//命令错误
}
}
在Web.Config配置文件中需要对APIHttpHandler对象进行配置
总结一下,Web版页面调用后台控制器的过程,利用Ajax发送Http请求被APIHttpHandler对象接收,APIHttpHandler对象解析Http请求通过反射创建控制器对象并执行方法,最后讲结果用Json格式输出到页面;
相关资料:
关于HttpHandlers和HttpModules的不同
http://www.cnblogs.com/ricksun/articles/1545491.html
httpModules 与 httpHandlers
http://www.cnblogs.com/chenlulouis/archive/2009/12/18/1626918.html
二、Winform版系统启动入口
Winform版是一个两层结构的程序,客户端和服务端,服务端就是数据库,每一个客户端运行都是独立的程序运行环境,Winform版客户端就是一个Windows窗体应用程序,所以我们直接找启动项目的Program类的Main函数;
上面AppGlobal_Init()是通过界面FrmSplash用委托的方式调用的,这是由于系统做初始化的时候需要一定时间,为了让用户觉得程序正在运行,显示一个正在加载的界面效果比较好;我们接着看AppGlobal_Init()函数代码,这里会读配置文件中值,进行判断是Winform还是WCFClient方式,本节先说Winform方式,先执行AppGlobal.AppStart(AppGlobalType.Winform)进行系统初始化,AppGlobal对象封装了所有模式的初始化代码;
到此Winform版的初始化入口就讲完了,AppGlobal对象最后一节我们再看;Winform版是三种模式中相对最容易看懂的了;
另外再讲一下Winform版的操作请求流程,系统登录进入菜单主界面后,点击菜单按钮就会打开窗体界面,我们讲讲这个过程的实现代码。
先找到按钮的点击事件,从菜单的Tag对象获取菜单的配置信息,最后调用ShowForm(winmenu)方法;
//点击菜单
void btnmenu_Click(object sender, EventArgs e)
{
btnImage = sender;
BaseItem baseItem = sender as BaseItem; if (baseItem.Tag.ToString() != "" && baseItem.Tag.GetType() != typeof(BaseModule))
{
BaseMenu menu = (BaseMenu)baseItem.Tag; WinMenu winmenu = new WinMenu();
if (Program.clienttype == "Winform")
{
winmenu.DllName = menu.DllName;
winmenu.FunName = menu.FunName;
}
else if (Program.clienttype == "WCFClient")
{
string[] names = menu.FunWcfName.Split(new char[] { '@' });
if (names.Length == )
{
winmenu.DllName = names[];
winmenu.FunName = names[];
}
}
else if (Program.clienttype == "WEBClient")
{
winmenu.DllName = "";
winmenu.FunName = "";
} //winmenu.DllName = menu.DllName;
//winmenu.FunName = menu.FunName;
winmenu.IsOutlookBar = menu.MenuLookBar;
winmenu.IsToolBar = menu.MenuToolBar;
winmenu.Memo = menu.Memo;
winmenu.MenuId = menu.MenuId;
winmenu.ModuleId = menu.ModuleId;
winmenu.Name = menu.Name;
winmenu.PMenuId = menu.PMenuId;
winmenu.SortId = menu.SortId;
winmenu.UrlPath = System.Configuration.ConfigurationSettings.AppSettings["WEB_serverUrl"] + menu.UrlName; ShowForm(winmenu);
}
}
打开ShowForm()方法的代码,这段代码的意思就是找到需要打开的界面Form对象,在显示在主界面的Tab中;其中BaseController basec = ControllerCreatorFactory.ControllerCreator(menu, delegateCloseTable)是本段代码的重点,调用此方法创建控制器对象,并获取控制器包含的界面Form;
public void ShowForm(WinMenu menu)
{
int index = this.barMainContainer.Items.IndexOf(menu.MenuId.ToString());
if (index < )
{
if (string.IsNullOrEmpty(menu.FunName) == false || string.IsNullOrEmpty(menu.UrlPath) == false)
{
#region winform界面
List<DockContainerItem> listitem = new List<DockContainerItem>(); CloseTab delegateCloseTable = delegate()
{
foreach (DockContainerItem item in listitem)
barMainContainer.CloseDockTab(item);
}; Form form = null;
if (Program.clienttype == "Winform")
{
BaseController basec = ControllerCreatorFactory.ControllerCreator(menu, delegateCloseTable);
if (string.IsNullOrEmpty(menu.FunName) == false)
{
string[] funs = menu.FunName.Split(new char[] { '|' });
if (funs.Length == )
form = (Form)basec.DefaultView;
else
form = (Form)basec.iBaseView[funs[]];
}else
form = (Form)basec.DefaultView;
}
else if (Program.clienttype == "WCFClient")
{
//string dllfile = menu.DllName;
//string controllername = menu.FunName.Split(new char[] { '|' })[0];
BaseWCFClientController basec = ControllerCreatorFactory.WCFControllerCreator(menu, delegateCloseTable);
if (string.IsNullOrEmpty(menu.FunName) == false)
{
string[] funs = menu.FunName.Split(new char[] { '|' });
if (funs.Length == )
form = (Form)basec.DefaultView;
else
form = (Form)basec.iBaseView[funs[]];
}
else
form = (Form)basec.DefaultView;
} if (form != null)
{
barMainContainer.BeginInit();
int displayWay = EFWCoreLib.WinformFrame.Common.CustomConfigManager.GetDisplayWay();//显示方式 0 标准 1全屏
if (displayWay == )
form.Dock = DockStyle.Fill;
form.Size = new Size(, );
form.FormBorderStyle = FormBorderStyle.None;
form.TopLevel = false;
if (this.barMainContainer.Width > form.Width)
{
form.Location = new Point((barMainContainer.Width - form.Width) / , );
}
else
form.Location = new Point(, );
form.Show(); PanelDockContainer panelDockMain = new PanelDockContainer();
panelDockMain.Dock = DockStyle.Fill;
panelDockMain.Controls.Add(form);
panelDockMain.Location = new System.Drawing.Point(, );
panelDockMain.Style.Alignment = System.Drawing.StringAlignment.Center;
panelDockMain.Style.GradientAngle = ;
panelDockMain.BackColor = Color.FromArgb(, , );
panelDockMain.AutoScroll = true; DockContainerItem item = new DockContainerItem(form.Text);
item.Text = menu.Name;
item.Name = menu.MenuId.ToString();
item.Control = panelDockMain;
item.Visible = true;
item.Tag = form;//绑定界面对象
item.Image = GetButtonImage(btnImage); item.VisibleChanged += new EventHandler(item_VisibleChanged);
//this.barMainContainer.Controls.Add(panelDockMain);
this.barMainContainer.Items.Add(item);
this.barMainContainer.SelectedDockContainerItem = item; listitem.Add(item); barMainContainer.EndInit();
this.barMainContainer.Show();
}
#endregion
}
}
else
{
this.barMainContainer.SelectedDockContainerItem = (DockContainerItem)this.barMainContainer.Items[index];
string formname = ((DockContainerItem)this.barMainContainer.Items[index]).Tag.GetType().Name;
if (formname == "FrmWebBrowser")
{
EFWCoreLib.WinformFrame.WebBrowser.IfrmWebBrowserView webbrowser = (EFWCoreLib.WinformFrame.WebBrowser.IfrmWebBrowserView)((DockContainerItem)this.barMainContainer.Items[index]).Tag;
webbrowser.NavigateUrl();//重新加载网址
}
} }
接着我们将ControllerCreatorFactory创建控制器的工厂类,所以这里使用了一个工厂模型用来创建不同的控制器,包含Winform界面控制器、WcfClient界面控制器和浏览器界面控制器;我们这里先看创建Winform界面控制器的实现方法InstanceController();此方法通过菜单配置的控制器名称,利用反射机制找到控制器与控制器自定义标签定义的界面Form,这样主界面就可以显示此界面Form在Tab页中;
public override Object InstanceController(CloseTab close)
{
try
{ //加载类库
Assembly assembly = null;
assembly = Assembly.LoadFrom(AppGlobal.AppRootPath + "\\" + dllfile); //获得控制器类(型)
Type type = assembly.GetType(controllername, false, true); MenuAttribute[] menuAttribute = (MenuAttribute[])type.GetCustomAttributes(typeof(MenuAttribute), true);
ViewAttribute[] viewAttribute = (ViewAttribute[])type.GetCustomAttributes(typeof(ViewAttribute), true);
//ServiceAttribute[] serviceAttribute = (ServiceAttribute[])type.GetCustomAttributes(typeof(ServiceAttribute), true); if (menuAttribute.Length > )
{
Dictionary<string, IBaseView> viewDic = new Dictionary<string, IBaseView>();
//Dictionary<string, SoapHttpClientProtocol> serviceDic = new Dictionary<string, SoapHttpClientProtocol>();
BaseController controller = (BaseController)System.Activator.CreateInstance(type); EFWCoreLib.CoreFrame.DbProvider.AbstractDatabase Rdb = EFWCoreLib.CoreFrame.DbProvider.FactoryDatabase.GetDatabase();
Rdb.WorkId = controller.GetSysLoginRight.WorkId;
controller.BindDb(Rdb, AppGlobal.container); controller.closeTab = close;//关闭窗口 for (int index = ; index < viewAttribute.Length; index++)
{
if (viewAttribute[index].ViewType == null)
{
if (string.IsNullOrEmpty(viewAttribute[index].DllName))
{
continue;
}
Assembly _assembly = Assembly.LoadFrom(AppGlobal.AppRootPath + "\\" + viewAttribute[index].DllName);
viewAttribute[index].ViewType = _assembly.GetType(viewAttribute[index].ViewTypeName, false, true);
}
IBaseView view = (IBaseView)System.Activator.CreateInstance(viewAttribute[index].ViewType);
if (viewAttribute[index].DefaultView) controller._defaultView = view;
if (index == && viewAttribute.ToList().FindIndex(x => x.DefaultView == true) == -) controller._defaultView = view;
viewDic.Add(viewAttribute[index].ViewType.Name, view);
}
//for (int index = 0; index < serviceAttribute.Length; index++)
//{
// SoapHttpClientProtocol service = (SoapHttpClientProtocol)System.Activator.CreateInstance(serviceAttribute[index].ServiceType);
// serviceDic.Add(serviceAttribute[index].ServiceType.Name, service);
//} controller.iBaseView = viewDic;
//controller.service = serviceDic; controller.Init();//初始化
return controller;
} return null;
}
catch (Exception err)
{
throw err;
}
}
总结一下Winform版调用控制器的过程,点击菜单按钮根据菜单的配置信息,ViewCreator对象创建对应的控制器,显示控制器自定义标签包含的界面;接着界面可以通过InvokeController方法执行控制器中的代码;
三、Wcf版系统启动入口
Wcf版是三层结构的程序,包括客户端、中间件和数据库,其中客户端的启动入口与上面Winform版的差不多,实现的方式一样的,用配置参数ClientType进行区分;重点讲一下中间件WCFHosting服务主机的启动入口;
查看WCFHosting程序点击启动按钮的事件代码,代码打开一个WCF的ServiceHost,绑定WCFHandlerService对象;
private void StartAppHost()
{
Loader.hostwcfclientinfoList = new HostWCFClientInfoListHandler(BindGridClient);
Loader.hostwcfMsg = new HostWCFMsgHandler(AddMsg); mAppHost = new ServiceHost(typeof(WCFHandlerService)); ServiceMetadataBehavior smb = mAppHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
mAppHost.Description.Behaviors.Add(new ServiceMetadataBehavior());
}
mAppHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex"); mAppHost.Open(); AddMsg(DateTime.Now, "WCF主机启动完成"); }
接着查看WCFHandlerService服务对象代码,执行构造函数调用了 AppGlobal.AppStart(AppGlobalType.WCF)进行系统初始化;
public WCFHandlerService()
{
//mCallBackList = new List<IClientService>();
Loader.ShowHostMsg(DateTime.Now, "WCFHandlerService服务正在初始化...");
AppGlobal.AppRootPath = System.Windows.Forms.Application.StartupPath + "\\";
AppGlobal.AppStart(AppGlobalType.WCF);
Loader.ShowHostMsg(DateTime.Now, "WCFHandlerService服务初始化完成"); if (Convert.ToInt32(HostSettingConfig.GetValue("heartbeat")) == )
Loader.StartListenClients();
}
服务主机的启动过程就是这样,接着我们再讲一下WCF版的客户端向WCFHosting中间件请求的流程;先看客户端控制器调用Wcf服务的代码,是通过InvokeWCFService方法指定后台wcf控制器的名称和方法名;
接着看InvokeWCFService方法的实现代码,通过调用WCFService对象的ProcessRequest来执行WCFHandlerService服务;这段代码利用wcf服务实现了客户端和中间件之间的通讯;
public virtual Object InvokeWCFService(string controller, string method, string jsondata)
{ string retJson;
using (var scope = new OperationContextScope(WCFService as IContextChannel))
{
var router = System.ServiceModel.Channels.MessageHeader.CreateHeader("routerID", myNamespace, AppGlobal.cache.GetData("routerID").ToString());
OperationContext.Current.OutgoingMessageHeaders.Add(router);
retJson = WCFService.ProcessRequest(ClientID, controller, method, jsondata);
}
object Result = JavaScriptConvert.DeserializeObject(retJson);
int ret = Convert.ToInt32(((Newtonsoft.Json.JavaScriptObject)(Result))["flag"]);
string msg = ((Newtonsoft.Json.JavaScriptObject)(Result))["msg"].ToString();
if (ret == )
{
throw new Exception(msg);
}
else
{
return ((Newtonsoft.Json.JavaScriptObject)(Result))["data"];
}
}
再接着看WCFHandlerService服务对于ProcessRequest方法的实现,通过参数传递的控制器名称和方法名称利用反射机制执行wcf控制器中的代码;
public string ProcessRequest(string mProxyID, string controller, string method, string jsondata)
{
try
{
if (Convert.ToInt32(HostSettingConfig.GetValue("debug")) == )
Loader.ShowHostMsg(DateTime.Now, "客户端[" + mProxyID + "]正在执行:" + controller + "." + method + "(" + jsondata + ")");
string retJson = Loader.ProcessRequest(mProxyID, controller, method, jsondata);
return "{\"flag\":0,\"msg\":" + "\"\"" + ",\"data\":" + retJson + "}";
}
catch (Exception err)
{
if (err.InnerException == null)
{
Loader.ShowHostMsg(DateTime.Now, "客户端[" + mProxyID + "]执行失败:" + controller + "." + method + "(" + jsondata + ")\n错误原因:" + err.Message);
return "{\"flag\":1,\"msg\":" + "\"" + err.Message + "\"" + "}";
}
else
{
Loader.ShowHostMsg(DateTime.Now, "客户端[" + mProxyID + "]执行失败:" + controller + "." + method + "(" + jsondata + ")\n错误原因:" + err.InnerException.Message);
return "{\"flag\":1,\"msg\":" + "\"" + err.InnerException.Message + "\"" + "}";
}
}
}
public static string ProcessRequest(string mProxyID, string controller, string method, string jsondata)
{
if (remoteLoaderDic[mProxyID] != null)
{
RemoteLoaderController mRemoteLoader = remoteLoaderDic[mProxyID];
return mRemoteLoader.InvokeController(wcfClientDic[mProxyID], controller, method, jsondata);
}
return "";
}
public string InvokeController(WCFClientInfo clientinfo, string controller, string method, string jsondata)
{
try
{
//ViewHandler = _viewH;
object[] paramValue = null;//jsondata?
object retObj = null;
string retJson = null; List<Cmd_WCFController> cmd = (List<Cmd_WCFController>)AppGlobal.cache.GetData("cmdWcfController");
Cmd_WCFController cmdC = cmd.Find(x => x.controllerName == controller);
if (cmdC != null)
{
cmdC.wcfController.ParamJsonData = jsondata;
cmdC.wcfController.ClientInfo = clientinfo;
Cmd_WCFMethod cmdM = cmdC.cmdMethod.Find(x => x.methodName == method);
if (cmdM != null)
{
if (controller == "LoginController" || controller == "TestWCFController")
{
}
else
{
if (System.Configuration.ConfigurationManager.AppSettings["TurnOnLoginRight"] == "true" && clientinfo.LoginRight == null)
{
//context.Response.Write("nologin");//没登陆
throw new Exception("没登陆");
}
} //每次请求控制器必须创建一个新的数据库链接
EFWCoreLib.CoreFrame.DbProvider.AbstractDatabase Rdb = EFWCoreLib.CoreFrame.DbProvider.FactoryDatabase.GetDatabase();
Rdb.WorkId = cmdC.wcfController.GetSysLoginRight.WorkId;
//创建数据库连接
cmdC.wcfController.BindDb(Rdb, AppGlobal.container); if (cmdM.dbkeys != null && cmdM.dbkeys.Count > )
{
cmdC.wcfController.BindMoreDb(Rdb, "default");
foreach (string dbkey in cmdM.dbkeys)
{
EFWCoreLib.CoreFrame.DbProvider.AbstractDatabase _Rdb = EFWCoreLib.CoreFrame.DbProvider.FactoryDatabase.GetDatabase(dbkey);
_Rdb.WorkId = cmdC.wcfController.GetSysLoginRight.WorkId;
//创建数据库连接
cmdC.wcfController.BindMoreDb(_Rdb, dbkey);
}
}
retObj = cmdM.methodInfo.Invoke(cmdC.wcfController, paramValue);
}
else
{
//context.Response.Write("error");//命令错误
throw new Exception("控制器[" + cmdC.controllerName + "],没有[" + cmdM.methodName + "]方法!");
}
}
else
{
//context.Response.Write("error");//命令错误
throw new Exception("没有控制器[" + cmdC.controllerName + "]");
}
if (retObj != null)
retJson = retObj.ToString();
return retJson;
}
catch (Exception ex)
{
if (ex.InnerException == null)
throw new Exception(ex.Message);
else
throw new Exception(ex.InnerException.Message);
}
}
总结一下wcf版的客户端向中间件发送请求的过程,客户端控制器利用WCFHandlerService服务通讯中间件,并发送需要执行的控制器名称和方法,中间件WCFHandlerService服务接收请求并根据参数利用反射调用wcf控制器的代码返回执行结果;
四、启动后初始化内容
通过上面对系统启动入口的讲解我们知道所有模式的初始化内容都是封装在AppGlobal对象中的,初始化的类型包括四种Web、Winform、WCF、WCFClient;WCFClient类型最简单,只要创建EntLib中的缓存对象;另外三种类型内容包括:
1)EntLib中的Unity对象、Cache对象
2)定义定时任务、委托代码对象
3)配置信息,BusinessDll、IsSaas、EFWUnity
4)Web类型加载实体、web控制器、WebService服务
5)WCF类型加载实体、wcf控制器
6)Winform类型加载实体
7)初始化定时任务、委托代码和系统启动停止扩展
8)测试数据库连接
再就是对启动的过程进行了日志记录,还有整个过程在系统中只能执行一次;
public enum AppGlobalType { Web,Winform,WCF,WCFClient }
AppGlobal对象代码
/// <summary>
/// 系统启动前初始化环境
/// </summary>
public class AppGlobal
{
/// <summary>
/// 应用程序根目录
/// </summary>
public static string AppRootPath; /// <summary>
/// 逻辑层程序集
/// </summary>
public static List<string> BusinessDll; /// <summary>
/// 是否启动成功
/// </summary>
public static bool IsRun = false;
/// <summary>
/// 是否Saas模式,where条件是否加workid
/// </summary>
public static bool IsSaas = false; /// <summary>
/// Unity对象容器
/// </summary>
public static IUnityContainer container;
/// <summary>
/// 企业库缓存
/// </summary>
public static ICacheManager cache; /// <summary>
/// 定制任务
/// </summary>
public static List<TimingTask> taskList; /// <summary>
/// 委托代码
/// </summary>
public static Hashtable codeList; private static bool _isCalled = false; private static object locker = new object(); public static void AppStart(AppGlobalType appType)
{
lock (locker)
{
if (_isCalled == false)
{
try
{
WriterLog("--------------------------------");
WriterLog("应用开始启动!");
if (appType == AppGlobalType.WCFClient)
{
cache = ZhyContainer.CreateCache();
}
else
{
//初始化静态变量
container = ZhyContainer.CreateUnity();
cache = ZhyContainer.CreateCache();
taskList = new List<TimingTask>();
codeList = new Hashtable();
//加载引用业务程序集
BusinessDll = new List<string>();
string[] dllfiles = System.Configuration.ConfigurationManager.AppSettings["BusinessDll"].Split(new char[] { '|' });
BusinessDll = dllfiles.ToList(); IsSaas = System.Configuration.ConfigurationManager.AppSettings["IsSaas"] == "true" ? true : false;
//加载Unity配置
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = AppRootPath + "Config/EFWUnity.config" };
System.Configuration.Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
var unitySection = (UnityConfigurationSection)configuration.GetSection("unity");
ZhyContainer.AddUnity(unitySection);//判断EntLib的路径对不对 if (BusinessDll.Count > )
{
switch (appType)
{
case AppGlobalType.Web:
//加载Entity自定义配置
EFWCoreLib.CoreFrame.BusinessArchitecture.Entity_Attribute.LoadEntityAttribute(AppRootPath+"bin/",BusinessDll, cache);
//加载WebController到缓存(此地方可能存在并发BUG)
EFWCoreLib.WebFrame.Controller.Cmd_Controller.LoadCmdController(BusinessDll, cache);
EFWCoreLib.WebFrame.HttpHandler.WebServiceInvoker.LoadWebService(BusinessDll, cache);
break;
case AppGlobalType.WCF:
//加载Entity自定义配置
EFWCoreLib.CoreFrame.BusinessArchitecture.Entity_Attribute.LoadEntityAttribute(AppRootPath, BusinessDll, cache);
EFWCoreLib.WCFHandler.Cmd_WCFController.LoadCmdController(BusinessDll, cache);
break;
case AppGlobalType.Winform:
//加载Entity自定义配置
EFWCoreLib.CoreFrame.BusinessArchitecture.Entity_Attribute.LoadEntityAttribute(AppRootPath, BusinessDll, cache);
break;
}
}
//初始化Web定制任务
MultiTask.Init(container, taskList);//任务
//是否开启Web控制器请求权限认证 //扩展Global,网站程序启动、停止可自定义代码
GlobalExtend.StartInit();
//初始化委托代码
ExecuteFun.Init(container, codeList);//执行函数 //测试数据库连接
EFWCoreLib.CoreFrame.DbProvider.FactoryDatabase.TestDbConnection(); }
_isCalled = true;
WriterLog("应用启动成功!");
WriterLog("--------------------------------"); IsRun = true;
}
catch(Exception err)
{
AppGlobal.WriterLog("应用启动失败!");
AppGlobal.WriterLog("--------------------------------");
throw err;
}
}
}
} public static void AppStart()
{
AppStart(AppGlobalType.WCF);
} public static void AppEnd()
{
GlobalExtend.EndInit();
} public static void WriterLog(string info)
{
info = "时间:" + DateTime.Now.ToString() + "\t\t" + "内容:" + info + "\r\n";
File.AppendAllText(AppRootPath + "startlog.txt", info);
} }
五、系统启动入口与操作请求流程
十五、EnterpriseFrameWork框架核心类库之系统启动入口与初始化的更多相关文章
- 十二、EnterpriseFrameWork框架核心类库之与EntLib结合
从本章开始对框架的讲叙开始进入核心类库的讲解,前面都是对框架外在功能讲解,让人有个整体的概念,知道包含哪些功能与对系统开发有什么帮助.以后多章都是讲解核心类库的,讲解的方式基本按照代码的目录结构,这样 ...
- 十八、【开源】EnterpriseFrameWork框架核心类库之Winform控制器
回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U EFW框架中的WinContro ...
- 十六、【适合中小企业的.Net轻量级开源框架】EnterpriseFrameWork框架核心类库之单点登录SSO
回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U 单点登录(Single Sign ...
- 十七、EnterpriseFrameWork框架核心类库之Web控制器
回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U EFW框架中的WebContro ...
- 十四、EnterpriseFrameWork框架核心类库之简易ORM
在写本章前先去网上找了一下关于ORM的相关资料,以为本章做准备,发现很多东西今天才了解,所以在这里也对ORM做不了太深入的分析,但还是浅谈一下EFW框架中的设计的简易ORM:文中有一点讲得很有道理,D ...
- 十三、EnterpriseFrameWork框架核心类库之数据库操作(多数据库事务处理)
本章介绍框架中封装的数据库操作的一些功能,在实现的过程中费了不少心思,针对不同数据库的操作(SQLServer.Oracle.DB2)这方面还是比较简单的,用工厂模式就能很好解决,反而是在多数据库同时 ...
- x264代码剖析(十五):核心算法之宏块编码中的变换编码
x264代码剖析(十五):核心算法之宏块编码中的变换编码 为了进一步节省图像的传输码率.须要对图像进行压缩,通常採用变换编码及量化来消除图像中的相关性以降低图像编码的动态范围.本文主要介绍变换编码的相 ...
- 十、EnterpriseFrameWork框架的分层架构及意义(控制器、业务对象、实体、Dao之间关系)
本章内容主要包括两个方面,一.是框架分层(控制器.业务对象.实体.Dao)的详细说明,二.是对比常用三层结构的区别和优势: 本文要点: 1.框架中的各个分层详细说明 2.对比常用三层结构的区别和优势 ...
- 二十、【.Net开源】EFW框架核心类库之WebService服务
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.1:http://pan.baidu.com/s/1qWJjo3U EFW框架实例源代码下载:http://pan.baid ...
随机推荐
- iOS企业级开发
2015移动技术白皮书 Android篇 iOS篇 项目管理篇 综合篇 结束语 iOS项目框架设计 项目结构的设计 基类的设计 自定义生命周期 跳转器 自定义UV打点控件 图片缓存 iOS网络底层框架 ...
- Gaussian分布下Hinge损失的期望
SVM的标准形式是\begin{align*} \min_{\boldsymbol{w}} \ \ \ \frac{\lambda}{2} \|\boldsymbol{w}\|^2 + \frac{1 ...
- LINQ-to-SQL那点事~LINQ-to-SQL中的数据缓存与应对
回到目录 这个文章写的有点滞后了,呵呵,因为总想把之前不确定的东西确定了之后,再写这篇,之前的LINQ-to-SQL那点事,请点这里. LINQ-to-SQL中的数据缓存与应对 Linq-to-SQL ...
- 记录js的一些小技巧
1.取数组最大值,最小值 Math.max.apply(null,[1,2,3,32,3]); Math.min.apply(null,[1,2,3,32,3]); 2.旧版IE setTimeout ...
- BOM (Browser Object Model) 浏览器对象模型
l对象的角色,因此所有在全局作用域中声明的变量/函数都会变成window对象的属性和方法; // PS:尝试访问未声明的变量会抛出错误,但是通过查询window对象,可以知道某个可能未声明的对象是否存 ...
- Spring3.2.4集成quartz2.2.1定时任务(demo).
在JavaEE系统中,我们会经常用到定时任务,下面是我自己写的一个demo. 前面几篇quartz博客感觉看的还是难懂 于是重新整理下 源码地址:http://pan.baidu.com/s/1BXH ...
- C#Winform程序如何发布并自动升级(图解)
C#Winform程序如何发布并自动升级(图解) 有不少朋友问到C#Winform程序怎么样配置升级,怎么样打包,怎么样发布的,在这里我解释一下打包和发布 关于打包的大家可以看我的文章C# w ...
- JVM中的Stack和Frame
JVM执行Java程序时需要装载各种数据,比如类型信息(Class).类型实例(Instance).常量数据(Constant).本地变量等.不同的数据存放在不同的内存区中,这些数据内存区称作“运行时 ...
- Delphi 2 Unleashed (一) 介绍
原书作者是作者是 Charles Calvert,国内翻译为<Delphi 2 程序设计大全>,由横空翻译组翻译,机械工业出版社1997年12月出版,看网上评论和介绍,该书是系统学习 De ...
- 编译Ngnix遇到的问题,查看程序依赖的库文件
要点:ldd 可以读取每个可以运行的程序依赖的 so 文件. 编译的时候提示需要Openssl库. 查看本机,已经安装了openssl 查看编译报错文件,查找Openssl所依赖的库 more obj ...