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); } }
配置文件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>
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
有时候因为一个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 ); } }
有关路由,请参考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, "ruanmouContainer"); return container; } }
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); } }
步骤:
1、自己定义一个类,继承DefaultControllerFactory
2、SetFactory,实例化控制器会进到这里
3、引入第三方容器,将控制器的实例化换成容器操作
这样就完成了MVC+IOC的结合。