摘要
本文为自用.NET相关第三方框架与组件笔记。
知识点内容根据各个教程收集整理。
所有教程版权归各自作者所有。
这里只做临时记录,对于笔记相对完整的框架/组件,将单独分离出来形成独立文档。
JQuery
示例
$(this).hide():隐藏当前的 HTML 元素。
$("#test").hide():隐藏 id="test" 的元素。
$("p").hide():隐藏所有<p>元素。
$(".test").hide():隐藏所有 class="test" 的元素。
语法
jQuery 语法是为 HTML 元素的选取编制的,可以对元素执行某些操作。
基础语法是:$(selector).action()
- 美元符号定义
jQuery
- 选择符(selector)“查询”和“查找” HTML 元素
jQuery 的 action() 执行对元素的操作
文档就绪函数
1 2 3
| $(document).ready(function(){ });
|
这是为了防止文档在完全加载(就绪)之前运行 jQuery 代码。
如果在文档没有完全加载之前就运行函数,操作可能失败。下面是两个具体的例子:
- 试图隐藏一个不存在的元素
- 获得未完全加载的图像的大小
选择器
元素选择器
jQuery 使用 CSS 选择器来选取 HTML 元素。
$("p") 选取 <p> 元素。
$("p.intro") 选取所有 class="intro" 的 <p> 元素。
$("p#demo") 选取所有 id="demo" 的 <p> 元素。
属性选择器
jQuery 使用 XPath 表达式来选择带有给定属性的元素。
$("[href]") 选取所有带有href属性的元素。
$("[href='#']") 选取所有带有 href 值等于 "#" 的元素。
$("[href!='#']") 选取所有带有 href 值不等于 "#" 的元素。
$("[href$='.jpg']") 选取所有 href 值以 ".jpg" 结尾的元素。
以上详见jQuery 教程
jQuery ajax - ajax() 方法
见jQuery ajax - ajax() 方法
SeriLog
Serilog是 .net 下的新兴的日志框架
示例
包Serilog是Log核心库,Serilog.Sinks.Console是Log的控制台输出库,这个也是日志框架的一贯策略,一个核心库加多个输出库组合使用,这样可以保持良好的扩展性。
1 2 3 4 5 6 7
| using (var log = new LoggerConfiguration() .WriteTo.Console() .CreateLogger()) { log.Information("Hello, Serilog!"); log.Warning("Goodbye, Serilog."); }
|
LoggerConfiguration
这里用了一个LoggerConfiguration对象,它主要用于创建和设置Log对象,类似于Nlog里面的LogManager类。这里主要用它两个方法:
WriteTo:WriteTo属性用来设置日志的输出,Serilog将其称为Sink(水槽),还是比较形象的。
CreateLogger:用于创建一个ILogger类型的Logger对象.
ILogger
ILogger对象用于记录日志,和其他日志框架差不多。Serilog日志级别分为如下5级
Verbose,
Debug,
Information,
Warning,
Error,
Fatal,
全局Logger对象
在实际的使用过程中,往往并不是每次使用都去创建一个ILogger,一种方式是通过依赖注入的方式创建一个全局的Logger。不过这种方式需要引入DI框架。在小程序中使用不算方便。
另一种方式是直接使用静态的Log类,它也携带了写入日志的方法,用起来非常方便。
1 2 3
| Log.Warning("warning"); Log.Error("err"); Log.Fatal("fatal");
|
不过Log类之前,首先必须给它关联一个ILogger。
1 2 3
| Log.Logger = new LoggerConfiguration() .WriteTo.Console() .CreateLogger();
|
SqlSugar
基本查询
详见基本查询
事务用法
1、单库事务
单库事务是针一个db操作执行的事务,无论是 ISqlSugarClient和 SqlSugarClient 用法都一样
1 2 3 4 5 6 7 8 9 10 11 12
| try { db.Ado.BeginTran(); db.Insertable(new Order() { .....}).ExecuteCommand(); db.Insertable(new Order() { .....}).ExecuteCommand(); db.Ado.CommitTran(); } catch (Exception ex) { db.Ado.RollbackTran(); throw ex; }
|
如果一个db就一个库,那么你也可以用多租户事务节约代码,因为2者在一个库的情况下作用一样
1 2 3 4
| db.BeginTran(); db.CommitTran(); db.RollbackTran();
|
来源详见事务用法
UnityContainer
IoC容器
注册实现
1 2 3 4 5 6 7 8
| public static void Main(string[] args) { UnityContainer unityContainer = new UnityContainer(); unityContainer.RegisterType<ITest, Test1>();
ITest testInstance1 = unityContainer.Resolve<ITest>(); testInstance1.SayHi(); }
|
注册多个不同名称实现
1 2 3 4 5 6 7 8 9 10 11 12 13
| public static void Main(string[] args) { UnityContainer unityContainer = new UnityContainer(); unityContainer.RegisterType<ITest, Test1>("type1"); unityContainer.RegisterType<ITest, Test2>("type2");
ITest testInstance1 = unityContainer.Resolve<ITest>("type1"); ITest testInstance2 = unityContainer.Resolve<ITest>("type2");
testInstance1.SayHi(); testInstance2.SayHi(); }
|
生命周期
TransientLifetimeManager - 为每次请求生成新的类型对象实例。 (默认行为)
ContainerControlledLifetimeManager - 实现 Singleton 对象实例。 当容器被 Disposed 后,对象实例也被 Disposed。
HierarchicalifetimeManager - 实现 Singleton 对象实例。但子容器并不共享父容器实例,而是创建针对字容器的 Singleton 对象实例。当容器被 Disposed 后,对象实例也被 Disposed。
ExternallyControlledLifetimeManager - 实现 Singleton 对象实例,但容器仅持有该对象的弱引用(WeakReference),所以该对象的生存期由外部引用控制。
PerThreadLifetimeManager - 为每个线程生成 Singleton 的对象实例,通过 ThreadStatic 实现。
PerResolveLifetimeManager - 实现与 TransientLifetimeManager 类似的行为,为每次请求生成新的类型对象实例。不同之处在于对象实例在 BuildUp 过程中是可被重用的。
Prism Core : Event Aggregator
事件聚合器
Prism 提供了一种机制,可以实现应用程序中松散耦合组件之间的通信。这种机制基于事件聚合器服务,允许发布者和订阅者通过事件进行通信,并且彼此之间仍然没有直接引用。
事件聚合器提供多播发布/订阅功能。这意味着可以有多个发布者引发相同的事件,并且可以有多个订阅者监听相同的事件。
通过事件聚合器服务可以使用IEventAggregator接口获取到事件聚合器。事件聚合器负责定位或构建事件,并在系统中保存事件的集合。首次访问一个事件时,如果该事件尚未构建,则构建。
事件类型
PubSubEvent是Prism中对积累EventBase的唯一实现。此类维护订阅者列表并向订阅者发送事件。PubSubEvent是一个泛型类,在使用时需要指定具体类型以进行特化。
一般是通过继承该类,特化一个自定义事件类型
发布
发布者通过事件聚合器服务获取到EventAggregator,并调用Publish方法来触发事件。
订阅
订阅者通过事件聚合器服务获取到EventAggregator,并调用Subscribe方法进行注册。之后,注册的事件被触发是,通过参数指定委托进行相应。
来源详见【Prism 8】事件聚合器(Event Aggregator)
步骤
- 继承
PubSubEvent<T>创建自定义事件类型
- 创建事件发送者
- 创建事件接收者,并订阅指定的事件
示例
首先定义 PubSubEvent:
1
| public class TestEvent:PubSubEvent<string>{}
|
发布方和订阅方都通过 EventAggregator 获得 PubSubEvent。
1 2 3 4 5 6 7 8
| public class MainPageViewModel { IEventAggregator _eventAggregator; public MainPageViewModel(IEventAggregator ea) { _eventAggregator = ea; } }
|
发送方需要通过 GetEvent 拿到 PubSubEvent,使用Publish()发布消息:
1
| _eventAggregator.GetEvent<TestEvent>().Publish("=_=");
|
订阅方使用这些消息,可以通过 Subscribe() 订阅事件:
1 2 3 4 5 6 7 8 9 10 11 12
| public class MainPageViewModel { public MainPageViewModel(IEventAggregator ea) { ea.GetEvent<TestEvent>().Subscribe(PrintLn); }
void PrintLn(string s) { Console.WriteLine(s); } }
|
来源详见[Windows] Prism 8.0 入门(上):Prism.Core
SignalR
.NET Core平台对于WebSocket的封装
示例
后端:实现Hub
1 2 3 4 5 6 7 8 9 10 11
| using Microsoft.AspNetCore.SignalR;
namespace TestHub{ class MyHub:Hub{ public Task SendPublicMsg(string msg){ string connId = this.Context.ConnctionId; string msgToSend = $"{connId} {DateTime.Now}:{msg}"; return this.Clients.All.SendAsync("PublicMsgReceived",msgToSend); } } }
|
配置:

配置中心(Hub)
在Program.cs中调用AddSignalR注册中心(Hub)所需的 SignalR 服务
1 2 3 4
| var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages(); builder.Services.AddSignalR();
|
使用MapHub配置端点(Endpoint):
1 2 3 4
| app.MapRazorPages(); app.MapHub<ChatHub>("/Chat");
app.Run();
|
创建和使用中心
创建一个继承Hub的类,并添加若干public方法使得客户端可以使用
1 2 3 4 5
| public class ChatHub : Hub { public async Task SendMessage(string user, string message) => await Clients.All.SendAsync("ReceiveMessage", user, message); }
|
向客户端发送消息
向客户端发还信息需要Client对象:
- 使用
Clients.All向所有客户端发送消息
- 使用
Clients.Caller向Caller发还消息
- 使用
Group("...")向特定组发送消息
1 2 3 4 5 6 7 8 9 10
| public async Task SendMessage(string user, string message) => await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message) => await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message) => await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
|
或避免字符串误拼写使用强类型中心Hub:
1 2 3 4 5 6 7 8 9 10 11
| public class StronglyTypedChatHub : Hub<IChatClient> { public async Task SendMessage(string user, string message) => await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message) => await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message) => await Clients.Group("SignalR Users").ReceiveMessage(user, message); }
|
客户端方法需要提前提取:
1 2 3 4
| public interface IChatClient { Task ReceiveMessage(string user, string message); }
|
强类型指定可以让编译器参与检查避免字符串误拼写
使用强类型 Hub<T> 会禁止使用 SendAsync。
从客户端请求结果
非强类型
在中心(Hub)方法中调用Client(...) 或 CallerClients 属性:
1 2 3 4 5 6 7 8 9
| public class ChatHub : Hub { public async Task<string> WaitForMessage(string connectionId) { var message = await Clients.Client(connectionId).InvokeAsync<string>( "GetMessage"); return message; } }
|
第二种方法是在IHubContext<T>的实例上调用Client(...):
1 2 3 4 5
| async Task SomeMethod(IHubContext<MyHub> context) { string result = await context.Clients.Client(connectionID).InvokeAsync<string>( "GetMessage"); }
|
强类型
强类型中心可以通过接口方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| public interface IClient { Task<string> GetMessage(); }
public class ChatHub : Hub<IClient> { public async Task<string> WaitForMessage(string connectionId) { string message = await Clients.Client(connectionId).GetMessage(); return message; } }
|
客户端
客户端使用On()返回结果
.NET参考:
1 2 3 4 5 6
| hubConnection.On("GetMessage", async () => { Console.WriteLine("Enter message:"); var message = await Console.In.ReadLineAsync(); return message; });
|
来源详见使用适用于 ASP.NET Core 的 SignalR 中的中心
Autofac
Autofac是第三方IOC容器,功能强大,比asp.netcore内置容器强大得多,支持属性注入和方法注入,支持AOP。
通过容器创建对象实例:
1 2 3 4
| ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>(); IContainer container = containerBuilder.Build(); Honer phone = container.Resolve<Honer>()
|
注册类型
普通类
通过 containerBuilder.RegisterType<>() 进行注册
1 2 3 4
| ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>(); IContainer container = containerBuilder.Build(); Honer phone = container.Resolve<Honer>();
|
抽象以及实现
通过 containerBuilder.RegisterType<>().As<>()
1 2 3 4
| ContainerBuilder containerBuilder = new ContainerBuilder(); containerBuilder.RegisterType<Honer>().As<IPhone>(); IContainer container = containerBuilder.Build(); IPhone phone = container.Resolve<IPhone>();
|
RegisterAssemblyTypes(程序集数组),程序集必须是public的
AsImplementedInterfaces():表示注册的类型,以接口的方式注册
PropertiesAutowired():支持属性注入
Where:满足条件类型注册
1 2 3 4 5 6 7 8 9 10
| var basePath = AppContext.BaseDirectory; var dll = Path.Combine(basePath, "MyAutofac.dll"); ContainerBuilder containerBuilder = new ContainerBuilder(); var assemblysServices = Assembly.LoadFrom(dll); containerBuilder.RegisterAssemblyTypes(assemblysServices) .Where(t => !t.Name.EndsWith("XXX")) .AsImplementedInterfaces() .PropertiesAutowired(); IContainer container = containerBuilder.Build(); ITeacher teacher = container.Resolve<ITeacher>();
|
注入方式
构造函数注入
默认选择参数最多的构造函数
1
| containerBuilder.RegisterType<Teacher>().As<ITeacher>();
|
全部属性注入
使用PropertiesAutowired(),对象所有属性全部注入
1
| containerBuilder.RegisterType<Teacher>().As<ITeacher>().PropertiesAutowired();
|
标记特性的属性注入
使用PropertiesAutowired,和特性选择器CustomPropertySelector
1 2 3 4 5 6 7 8 9 10 11
| containerBuilder.RegisterType<Teacher>().As<ITeacher>().PropertiesAutowired(new CustomPropertySelector());
public class CustomPropertySelector : IPropertySelector { public bool InjectProperty(PropertyInfo propertyInfo, object instance) { var flag = propertyInfo.CustomAttributes.Any(it => it.AttributeType == typeof(SelectPropAttribute)); return flag; } }
|
方法注入
使用OnActivated,指定调用方法
1 2 3 4 5
| containerBuilder.RegisterType<Teacher>().As<ITeacher>() .OnActivated(p => { p.Instance.SetStudent1(p.Context.Resolve<IStudent>()); });
|
生命周期
| 生命周期 |
名称 |
说明 |
InstancePerDependency |
瞬时生命周期 |
每次获取都是全新的实例,默认生命周期 |
SingleInstance |
单例生命周期 |
同一个进程内都是同一个实例 |
InstancePerLifetimeScope |
作用域生命周期 |
同一个作用域内都是同一个实例 |
InstancePerMatchingLifetimeScope |
作用域范围生命周期 |
在作用域范围里面,同一个作用域下面的对象是同一个;在作用域范围外无法创建实例 |
InstancePerRequest |
一次请求一个对象 |
只能在Web中使用,在控制台中使用会报错 |
使用:
1
| containerBuilder.RegisterType<Honer>().As<IPhone>().InstancePerDependency();
|