.NET框架
项目结构
- Connected Services是第三方服务
- MVC框架
- appsettings.json配置文件
- Program.cs控制台应用程序
- Properties里的json文件是配置启动方式
1. 基本开发
出现这个bug是因为防火墙没有把浏览器加入白名单,可以暂时先用http启动代替
- 第一步创建控制器(请求映射路径就是文件夹和文件名)
- 第二步在该控制器右键新建视图
- 启动
- 数据返回方式
//控制器
public IActionResult Index()
{ViewBag.User1 = "张三";ViewData["User2"] = "李四";TempData["User3"] = "王五";HttpContext.Session.SetString("User4", "赵六");object User5 = "田七";return View(User5);
}
//视图
@{ViewData["Title"] = "Hello,World";
}
@Model String
<h2>User1=@ViewBag.User1</h2>
<h2>User2=@ViewData["User2"]</h2>
<h2>User3=@TempData["User3"]</h2>
<h2>User4=@Context.Session.GetString("User4")</h2>
<h2>User5=@Model</h2>
//如果不配置Session服务就会报错
//到Program里面配置
builder.Service.AddSession();
var app = builder.Build();
app.UseSession();
2.日志log4net组件整合
导入依赖包
-
右键 => 管理解决方案
-
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
-
另外还要安装第二个组件Log4Net.AspNetCore
-
可以在依赖项里看到安装好的包
配置文件
-
文件结构(XML):<Log4Net,,>
-
<?xml version="1.0" encoding="utf-8"?> <log4net><!-- Define some output appenders --><appender name="rollingAppender" type="log4net.Appender.RollingFileAppender"><file value="log4\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="ALL" /><param name="LevelMax" value="FATAL" /></filter><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/></layout></appender><!--SqlServer形式--><!--log4net日志配置:http://logging.apache.org/log4net/release/config-examples.html --><appender name="AdoNetAppender_SqlServer" type="log4net.Appender.AdoNetAppender"><!--日志缓存写入条数 设置为0时只要有一条就立刻写到数据库--><bufferSize value="0" /><connectionType value="System.Data.SqlClient.SqlConnection,System.Data.SqlClient, Version=4.6.1.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /><connectionString value="Data Source=PC-202206030027;Initial Catalog=LogManager;Persist Security Info=True;User ID=sa;Password=sa123" /><commandText value="INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)" /><parameter><parameterName value="@log_date" /><dbType value="DateTime" /><layout type="log4net.Layout.RawTimeStampLayout" /></parameter><parameter><parameterName value="@thread" /><dbType value="String" /><size value="255" /><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%thread" /></layout></parameter><parameter><parameterName value="@log_level" /><dbType value="String" /><size value="50" /><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%level" /></layout></parameter><parameter><parameterName value="@logger" /><dbType value="String" /><size value="255" /><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%logger" /></layout></parameter><parameter><parameterName value="@message" /><dbType value="String" /><size value="4000" /><layout type="log4net.Layout.PatternLayout"><conversionPattern value="%message" /></layout></parameter><parameter><parameterName value="@exception" /><dbType value="String" /><size value="2000" /><layout type="log4net.Layout.ExceptionLayout" /></parameter></appender><root><!--控制级别,由低到高: ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF--><!--OFF:0--><!--FATAL:FATAL--><!--ERROR: ERROR,FATAL--><!--WARN: WARN,ERROR,FATAL--><!--INFO: INFO,WARN,ERROR,FATAL--><!--DEBUG: INFO,WARN,ERROR,FATAL--><!--ALL: DEBUG,INFO,WARN,ERROR,FATAL--> <priority value="ALL"/><level value="INFO"/><appender-ref ref="rollingAppender" /><appender-ref ref="AdoNetAppender_SqlServer" /></root> </log4net>
-
-
右键属性,将文件设置为copy if newer 或者 copy always(在编译的时候复制到bin文件夹)
-
在Program里导入
builder.Logging.AddLog4Net("同级目录/Log4Net.Config");
-
调用日志接口
- 构造函数注入
private readonly ILogger<Controller> _ILogger; public Controller(ILogger<Controller> ilogger){this._ILogger = ilogger; }
- 日志记录
_Ilogger.LogInformation("this is information"); _ILogger.LogError("this is Error"); _ILogger.LogWarning("this is Warning"); _ILogger.DeBug("this is DeBug");
数据库日志
先安装SQLClient(相同的方法,System.Data开头的)
因为是SQL Server 没学过,暂时放着
IOC容器之第三方组件Autofac
- 引入依赖Autofac和Autofac.Extensions.DependencyInjection都要
- IOC的意义在于,操作的对象可以是抽象,而不是具体的实现
- Autofac 是一个流行的依赖注入容器,它提供了许多高级功能,如自动装配、动态解析和生命周期管理。更多复杂的注入方式(属性注入、方法注入等)
- .NET 原生的依赖注入是随着 .NET Core 的推出而引入的,它更加轻量级,易于使用,支持基本的依赖注入模式,包括构造函数注入、服务生命周期管理。
- 单个类注入步骤
// 创建构造器ContainerBuilder builder = new ContainerBuilder();// 注册抽象与实现的隐射builder.RegisterType<Print>().As<IPrint>();// 泛型builder.RegisterGeneric(typeof(List<>)).As(typeof(IList<>));// 构建容器IContainer container = builder.Build();// 创建实例IPrint print = container.Resolve<IPrint>();IList<IPrint> prints = container.Resolve<IList<IPrint>>();// 打印Console.WriteLine(print.ToString());foreach (var item in prints){Console.WriteLine(item.ToString());}print.Print("This is Print");// 此外还有多种注册方式(实例注册、注册逻辑)
- 程序集注入
//将其他程序集引入可以使用右键依赖项然后引用
// 创建构造器
ContainerBuilder builder = new ContainerBuilder();// 假设我们有两个程序集,一个包含接口,另一个包含实现
Assembly interfaceAssembly = Assembly.LoadFrom("Interfaces.dll");//Interfaces是文件夹名称
Assembly implementationAssembly = Assembly.LoadFrom("Implementations.dll");// 使用这个方法注册时,会扫描程序集所有的接口、实现
// 注册接口程序集中的所有接口类型
builder.RegisterAssemblyTypes(interfaceAssembly).Where(t => t.IsInterface).AsImplementedInterfaces();// 注册实现程序集中的所有非接口类型(实现类)
builder.RegisterAssemblyTypes(implementationAssembly).Where(t => !t.IsInterface).AsImplementedInterfaces();// 构建容器
var container = builder.Build();// 尝试解析接口实例
var myService = container.Resolve<IMyService>();
// 其他写法
builder.RegisterAssemblyTypes(interfaceAssembly,implementationAssembly).AsImplementedInterfaces();
- 正常注册之后,是只会完成构造器注入,如果有属性不在构造器就必须使用属性注入
builder.RegisterType<Print>().As<IPrint>().PropertitiesAutowired;
-
方法注入,创建实例之后,方法自动执行,参数自动注入(略)
-
单抽象多实例,多个实现类注册,创建时默认生成最后注册的实现类
// 但也可以通过下面的方法来实现
builder.RegisterType<Print>().Keyed<IPrint>("NewPrint");
IPrint print = container.ResolveKeyed<IPrint>("NewPrint");
Autofac整合AOP
- 引入包 Castle.Core
- 编写相应的特性
public class CustomInterceptor : IInterceptor
{public void Intercept(IInvocation invocation){//方法执行前invocation.Proceed();//方法执行后}
}
- 放在对应的类上并且对应的方法要定义为虚拟
[Intercept(typeof(CustomInterceptor))]public virtual void Print()
{Console.WriteLine("方法执行")
}
- 注册
builder.RegisterType<Print>().As<IPrint>().EnableClassInterceptors();
整合Autofac
// Program.cs里builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());builder.Host.ConfigureContainer<ContainerBuilder>(Container =>{//注册服务});
// 整合程序集注册、单抽象多实例和AOP编程
using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using System;
using System.Reflection;// 定义接口
public interface IPrint
{void PrintMessage(string message);
}// 实现类
public class PrintA : IPrint
{public void PrintMessage(string message){Console.WriteLine($"PrintA: {message}");}
}public class PrintB : IPrint
{public void PrintMessage(string message){Console.WriteLine($"PrintB: {message}");}
}// AOP 拦截器
public class CallLogger : IInterceptor
{public void Intercept(IInvocation invocation){Console.WriteLine($"Before: {invocation.Method.Name}");invocation.Proceed();Console.WriteLine($"After: {invocation.Method.Name}");}
}class Program
{static void Main(string[] args){var builder = new ContainerBuilder();// 程序集注入var assembly = Assembly.GetExecutingAssembly();builder.RegisterAssemblyTypes(assembly).Where(t => t.Name.EndsWith("A")) // 假设以"A"结尾的类是我们要注册的.AsImplementedInterfaces().EnableClassInterceptors();// 单抽象多实例注册builder.RegisterType<PrintA>().Keyed<IPrint>("PrintA");builder.RegisterType<PrintB>().Keyed<IPrint>("PrintB");// 注册拦截器builder.Register(c => new CallLogger());var container = builder.Build();// 解析并使用服务var printA = container.ResolveKeyed<IPrint>("PrintA");var printB = container.ResolveKeyed<IPrint>("PrintB");printA.PrintMessage("Hello from PrintA");printB.PrintMessage("Hello from PrintB");}
}