MVCApplication Application_Statr--RegisterRoutes--給RouteCollection添加規則,請求進到網站 X 請求地址被路由按照順序匹配,遇到一個溫和的就結束,就到對應的控制器和action。 在程式中使用log4net,首先nuget引入程式集 L ...
MVCApplication---Application_Statr--RegisterRoutes--給RouteCollection添加規則,請求進到網站---X----請求地址被路由按照順序匹配,遇到一個溫和的就結束,就到對應的控制器和action。
在程式中使用log4net,首先nuget引入程式集
Logger代碼
public class Logger { static Logger() { XmlConfigurator.Configure(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CfgFiles\\log4net.config"))); ILog Log = LogManager.GetLogger(typeof(Logger)); Log.Info("系統初始化Logger模塊"); } private ILog loger = null; public Logger(Type type) { loger = LogManager.GetLogger(type); } /// <summary> /// Log4日誌 /// </summary> /// <param name="msg"></param> /// <param name="ex"></param> public void Error(string msg = "出現異常", Exception ex = null) { Console.WriteLine(msg); loger.Error(msg, ex); } /// <summary> /// Log4日誌 /// </summary> /// <param name="msg"></param> public void Warn(string msg) { Console.WriteLine(msg); loger.Warn(msg); } /// <summary> /// Log4日誌 /// </summary> /// <param name="msg"></param> public void Info(string msg) { Console.WriteLine(msg); loger.Info(msg); } /// <summary> /// Log4日誌 /// </summary> /// <param name="msg"></param> public void Debug(string msg) { Console.WriteLine(msg); loger.Debug(msg); } }View Code
配置文件log4net.config
<?xml version="1.0" encoding="utf-8"?> <log4net> <!-- Define some output appenders --> <appender name="rollingAppender" type="log4net.Appender.RollingFileAppender"> <file value="log\log.txt" /> <!--追加日誌內容--> <appendToFile value="true" /> <!--防止多線程時不能寫Log,官方說線程非安全--> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <!--可以為:Once|Size|Date|Composite--> <!--Composite為Size和Date的組合--> <rollingStyle value="Composite" /> <!--當備份文件時,為文件名加的尾碼--> <datePattern value="yyyyMMdd.TXT" /> <!--日誌最大個數,都是最新的--> <!--rollingStyle節點為Size時,只能有value個日誌--> <!--rollingStyle節點為Composite時,每天有value個日誌--> <maxSizeRollBackups value="20" /> <!--可用的單位:KB|MB|GB--> <maximumFileSize value="3MB" /> <!--置為true,當前最新日誌文件名永遠為file節中的名字--> <staticLogFileName value="true" /> <!--輸出級別在INFO和ERROR之間的日誌--> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="INFO" /> <param name="LevelMax" value="FATAL" /> </filter> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/> </layout> </appender> <!-- levels: OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL --> <root> <priority value="ALL"/> <level value="ALL"/> <appender-ref ref="rollingAppender" /> </root> </log4net>View Code
public class MvcApplication : System.Web.HttpApplication { private Logger logger = new Logger(typeof(MvcApplication)); protected void Application_Start() { AreaRegistration.RegisterAllAreas();//註冊區域 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);//註冊全局的Filter RouteConfig.RegisterRoutes(RouteTable.Routes);//註冊路由 BundleConfig.RegisterBundles(BundleTable.Bundles);//合併壓縮 ,打包工具 Combres this.logger.Info("網站啟動了。。。"); } }
Area
Area請參考博客:
http://www.cnblogs.com/zgqys1980/archive/2012/08/22/2650774.html
有時候因為一個Web項目可以非常大非常複雜,多人合作開發,命名就成問題了。Area可以把項目拆分開,方便團隊合作,演變到後面就可以做成插件式開發了:
MvcApplication--Application_Start--AreaRegistration.RegisterAllAreas()---其實就是把SystemAreaRegistration給註冊下---添加URL地址規則--請求來了就匹配(area在普通的之前)
眾所周知,MVC請求的最後是反射調用Controller+Action,信息來自於url+roy=ute,路由匹配時,只能找到Action和Controller,其實還有個步驟,掃描+存儲,在bin裡面找Controller的子類,然後把命名空間---類名稱+方法全部存起來。
控制器類可以出現在MVC項目之外,唯一的規則就是繼承自Controller,Area也可以獨立開,規則是必須有個繼承AreaRegistration。
public class SystemAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "System";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "System_default",
url: "System/{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
}
}
Razor語法:cshtml本質是一個類文件,混編了html+cs代碼
寫後臺代碼:行內--單行--多行--關鍵字
後臺代碼寫html:@: 閉合的html標簽 <text></text>
Html擴展控制項:封裝個方法,自動生成html
後端一次性完成全部內容,而且html標簽閉合
我們還可以自行封裝這種擴展方法
但是這個已經不流行了,就是UI改動需要重新發佈
更多應該是前後分離,寫前端的人是不會懂後端的寫法
Layout
Masterpage--layout 預設是_layout 可以自行指定
@Styles.Render("~/Content/css") 使用樣式包
@Scripts.Render("~/bundles/modernizr") 使用js包
@RenderBody() 就是頁面的結合點
@RenderSection("scripts", required: false)
partialPage局部頁---ascx控制項,是沒有自己的ACTION
@{ Html.RenderPartial("PartialPage", "這裡是Html.RenderPartial"); }
@Html.Partial("PartialPage", "這裡是Html.Partial")
子請求
@Html.Action("ChildAction", "Second", new { name = "Html.Action" })
@{Html.RenderAction("ChildAction", "Second", new { name = "Html.RenderAction" });}
有action,也可以傳參數
[ChildActionOnly]//只能被子請求訪問 不能獨立訪問
Asp.net MVC中Html.Partial, RenderPartial, Action,RenderAction 區別和用法請參考https://www.cnblogs.com/gesenkof99/archive/2013/06/03/3115052.html
Route
其實,路由這個東西,如果沒必要的話,還是不要隨便亂改了
下麵是路由的一些改動:
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //忽略路由 正則表達式 {resource}表示變數 a.axd/xxxx resource=a pathInfo=xxxx //.axd是歷史原因,最開始都是webform,請求都是.aspx尾碼,IIS根據尾碼轉發請求;MVC出現了,沒有尾碼,IIS6以及更早版本,打了個補丁,把mvc的請求加上個.axd的尾碼,然後這種都轉發到網站----新版本的IIS已經不需要了,遇到了就直接忽略,還是走原始流程 routes.IgnoreRoute("CustomService/{*pathInfo}");//以CustomService開頭,都不走路由 routes.MapRoute( name: "About", url: "About", defaults: new { controller = "Home", action = "About", id = UrlParameter.Optional } );//固定路由,/Home/About----About routes.MapRoute( name: "Test", url: "Test/{action}/{id}", defaults: new { controller = "Second", action = "Index", id = UrlParameter.Optional } );//修改控制器, routes.MapRoute( name: "Regex", url: "{controller}/{action}_{year}_{month}_{day}", defaults: new { controller = "Second", action = "Index", id = UrlParameter.Optional }, constraints: new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } ); //http://localhost:2017/second/Time_2019_06_13 Regex //http://localhost:2017/second/Time_2019_6_13 失敗 //http://localhost:2017/second/Time?year=2019&month=6&day=13 Default //http://localhost:2017/test/Time?year=2019&month=6&day=13 Test //http://localhost:2017/test/Time_2019_06_13 失敗的,只會被一個路由匹配 //常規路由,一般來說,我們不怎麼擴展這個路由 routes.MapRoute( name: "Default",//路由名稱,RouteCollection是key-value,key 避免重覆 url: "{controller}/{action}/{id}",//正則規則:兩個斜線 3個變數 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } //預設值 沒有id變數 就是UrlParameter.Optional 沒有action就是index 沒有controller是home ); } }View Code
有關路由,請參考https://www.tuicool.com/articles/ne2Qfe
IOC和MVC的結合,工廠的創建和Bussiness初始化
MVC請求進來,漏油匹配,找到控制器和Action,控制器是個普通的類,Action是個普通的實例方法,是不是有一個過程,叫實例化控制器?但是現在希望通過容器來實例化這個控制器。
路由匹配後得到控制器名稱--MVCHandler---ControllerBuilder.GetControllerFactory()---然後創建控制器的實例。
public class DIFactory { public static IUnityContainer GetContainer() { IUnityContainer container = null; //container.RegisterType ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config"); Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); container = new UnityContainer(); section.Configure(container, "Bingle"); return container; } }
不要每次都創建一個,判斷是否為null
/// <summary> /// 依賴註入工廠 /// </summary> public class DIFactory { private static object _SyncHelper = new object(); private static Dictionary<string, IUnityContainer> _UnityContainerDictionary = new Dictionary<string, IUnityContainer>(); /// <summary> /// 根據containerName獲取指定的container /// </summary> /// <param name="containerName">配置的containerName,預設為defaultContainer</param> /// <returns></returns> public static IUnityContainer GetContainer(string containerName) { if (!_UnityContainerDictionary.ContainsKey(containerName)) { lock (_SyncHelper) { if (!_UnityContainerDictionary.ContainsKey(containerName)) { //配置UnityContainer IUnityContainer container = new UnityContainer(); ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config"); Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); configSection.Configure(container, containerName); _UnityContainerDictionary.Add(containerName, container); } } } return _UnityContainerDictionary[containerName]; } }
ControllerBuilder有個SetControllerFactory。
public class BingleControllerFactory : DefaultControllerFactory { private Logger logger = new Logger(typeof(BingleControllerFactory)); protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { this.logger.Warn($"{controllerType.Name}被構造..."); IUnityContainer container = DIFactory.GetContainer(); //return base.GetControllerInstance(requestContext, controllerType); return (IController)container.Resolve(controllerType); } }
/// <summary> /// 自定義的控制器實例化工廠 /// </summary> public class UnityControllerFactory : DefaultControllerFactory { private IUnityContainer UnityContainer { get { return DIFactory.GetContainer(); } } /// <summary> /// 創建控制器對象 /// </summary> /// <param name="requestContext"></param> /// <param name="controllerType"></param> /// <returns></returns> protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if (null == controllerType) { return null; } IController controller = (IController)this.UnityContainer.Resolve(controllerType); return controller; } /// <summary> /// 釋放 /// </summary> /// <param name="controller"></param> public override void ReleaseController(IController controller) { //釋放對象 //this.UnityContainer.Teardown(controller);//釋放對象 Unity容器釋放對象只有單例那些,瞬時的是不存在釋放管理的,直接.net框架自身會即時完成對象釋放 /* I wrote an article about using object lifetimes managers in Unity and their impact on disposing. If you use default TransientLifetimeManager or PerResolveLifetimeManager the Unity will even don't track existence of your objects so it can't call Dispose. The only lifetime managers which calls Dispose on resolved instances are ContainerControlledLifetimeManager (aka singleton) and HierarchicalLifetimeManager. The Dispose is called when the lifetime manager is disposed. */ base.ReleaseController(controller);// } }
步驟:
1、自己定義一個類,繼承DefaultControllerFactory
2、SetFactory,實例化控制器會進到這裡
3、引入第三方容器,將控制器的實例化換成容器操作
這樣就完成了MVC+IOC的結合。