MVCApplication---Application_Statr--RegisterRoutes--給RouteCollection添加規則,請求進到網站---X----請求地址被路由按照順序匹配,遇到一個溫和的就結束,就到對應的控制器和action。css
在程序中使用log4net,首先nuget引入程序集html
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); } }
配置文件log4net.configweb
<?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>
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
衆所周知,MVC請求的最後是反射調用Controller+Action,信息來自於url+roy=ute,路由匹配時,只能找到Action和Controller,其實還有個步驟,掃描+存儲,在bin裏面找Controller的子類,而後把命名空間---類名稱+方法所有存起來。app
控制器類能夠出如今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 ); } }
有關路由,請參考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);// } }
步驟:
一、本身定義一個類,繼承DefaultControllerFactory
二、SetFactory,實例化控制器會進到這裏
三、引入第三方容器,將控制器的實例化換成容器操做
這樣就完成了MVC+IOC的結合。