.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");
}
}