MVC开发
- 什么是MVC?
V:视图------呈现给用户看到的内容(表现层)
C:控制器----控制业务逻辑计算,调用服务,选择返回什么内容,可以返回视图,JSON,字符串等等
M:视图模型—用作控制器和视图之间传递数据的载体
cshtml文件:其实是一个类文件;
当项目启动时,解决修改视图,不能立马生效问题?
- Nuget引入:Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation
- 在startup下的ConfigureServices方法中添加
services.AddRazorPages().AddRazorRuntimeCompilation();
Razor混编
可以在cshtml 上写上后台C#代码+前台html代码;混合起来
@using xxx.CustomInterface
@{
ViewData["Title"] = "Index";
}
@implements CustomInterface
@functions {
//实现接口
public void Show()
{
Console.WriteLine("实现接口");
}
}
@functions {
public string GetHello()
{
return "functions----Hello";
}
}
<div>From method: @GetHello()</div>
<h1>我是谁</h1>
@{int i = 3; int m = 4;} @*单行*@ <!--单行-->
@{
//多行
ViewBag.Title = "this is Second Page";
int k = 5;
}
@{
<h1>k=@k</h1>
}
@*行内 要么不要大括号 如果有大括号---内部的后台代码也需要@符号*@
<h3>
行内:@{
@ViewBag.Title
}
</h3>
<p>@DateTime.Now</p>
<p>@DateTime.IsLeapYear(2016)</p>
@*显式 Razor 表达式*@
<br />
<p>显式 Razor 表达式: @(DateTime.Now - TimeSpan.FromDays(7))</p>
@{
int index = 123;
}
@index
<br />
@("<span>Hello World</span>")//如果想要在页面上输初一个代码尖括号
<br />
@*代码块*@
@{
//可以声明变量+做计算+声明方法
var q = "hkhiuyh";
}
<p>@q</p>
<br />
@{
qs = "llllljuiljkl";
}
<p>@qs</p>
<br />
@*在代码块中,使用标记将本地函数声明为用作模板化方法:*@
@{
void RenderName(string name)
{
<p>Name: <strong>@name</strong></p>
}
RenderName("模板化方法:ccccccc");
RenderName("模板化方法:aaaaaa");
}
***********************************************
<br />
@*隐式转换*@
@{
var inCSharp = true;
<p>Now in HTML, was in C# @inCSharp</p>
}
<br />
@*带分隔符的显式转换*@
@{
var a= "学无止境";
}
@for (var x = 0; x < a.Length; x++)
{
var person = people[x];
<text>Name: @person</text>//标识为字符串文本
}
<br />
@*if*@
@{
int y = 3;
}
@if (y > 2)
{
<a href="www.baidu.com">这里是个百度的链接</a>
}
@for (int l = 0; l < 10; l++)
{
<a href="https://blog.csdn.net/CrtLife?spm=1011.2124.3001.5343">欢迎来到我的博客</a> //html
if (l == 0) //这个是后台代码
{
<a href="www.baidu.com">这里是百度链接 @l</a>
}
else if (l == 2)
{
<a href="https://blog.csdn.net/CrtLife?spm=1011.2124.3001.5343">欢迎来到我的博客</a>
}
else
{
<a href="https://blog.csdn.net/CrtLife?spm=1011.2124.3001.5343">欢迎来到我的博客</a>
}
<br>
}
@for (int l = 0; l < 5; l++)
{
@switch (l)
{
case 1:
<a href="https://blog.csdn.net/CrtLife?spm=1011.2124.3001.5343">欢迎来到我的博客</a>
break;
case 2:
<a href="https://blog.csdn.net/CrtLife?spm=1011.2124.3001.5343">欢迎来到我的博客</a>
break;
case 3:
<a href="https://blog.csdn.net/CrtLife?spm=1011.2124.3001.5343">欢迎来到我的博客</a>
break;
case 4:
<a href="https://blog.csdn.net/CrtLife?spm=1011.2124.3001.5343">欢迎来到我的博客</a>
break;
case 5:
<a href="https://blog.csdn.net/CrtLife?spm=1011.2124.3001.5343">欢迎来到我的博客</a>
break;
default:
break;
}
<br>
}
<br />
<br />
<!--后台代码内部如何写html-->
@{
//多行
ViewBag.Title = "Index";
//闭合的html标签
<p>闭合的html标签</p>
@:这里没有闭合标签
<text>
在这里,随便写html
<a href="https://blog.csdn.net/CrtLife?spm=1011.2124.3001.5343">欢迎来到我的博客</a>
</text>
}
Razor布局
我们看到的页面组成到底有哪些内容?
包含了Layout的母版嵌套的返回的需要渲染的视图内容;
如何嵌套呢?
通过Layout中RenderBody()方法做了替换;把返回的视图替换到母版页中;形成了一整块的内容;
目的在于在每一次返回不同的页面的时候,能够把不变的部分视图,做以重用;这样就可以少写代码;
在母版页中使用css,js的时候,为了提高效率,会把css,引入在母版的上方,js引入在下方;
页面嵌套到母版页后,就会出现在引入js的上方调用js,js 其实是调用不了的;
解决方案:
1.在母版页中,标记 @await RenderSectionAsync(“Scripts”, required: false)
2.在返回页面中,标记@section Scripts{} 把js代码写到到 @section Scripts{ } 大括号中,就可以解决;
Razor扩展控件
首先新建一个静态类
再定义一个Razor的扩展方法 代码如下
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebApplication6.Unity
{
public static class Htmlhelper
{
//自定义html 扩展方法
public static IHtmlContent Br(this IHtmlHelper helper)
{
return new HtmlString("<br/>");
}
}
}
然后在视图界面使用
@{
Layout = null;
}
@using WebApplication6.Unity //引入命名空间
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>View</title>
</head>
<body>
<div>
<span>你好</span>
@Html.Br()
<span>朋友</span>
</div>
</body>
</html>
结果
成功渲染成html标签
还有扩展控件的第二种方式
首先创建一个类该继承着一个抽象类代码如下
using Microsoft.AspNetCore.Razor.TagHelpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebApplication6.Unity
{
[HtmlTargetElement("Hello")] //html标记
public class TagHelpers : TagHelper
{
//规则:
//建议在定义属性的时候,首字母大写
public int Id { get; set; }
public string Age { get; set; }
public string Name { get; set; }
public TagHelpers()
{
}
//重写父类方法
public override void Process(TagHelperContext context, TagHelperOutput output)
{
int _id = Id; //接收参数
string _name = Name;
string _age = Age;
output.TagName = "div"; //定义要渲染的标签
output.Attributes.Add("namet", "张三"); //添加属性
output.PreContent.SetContent("欢迎进入到我的博客,和我一起学习吧"); //定义要显示的文本
}
}
}
@{
Layout = null;
}
@using WebApplication6.Unity
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>View</title>
</head>
<body>
<div>
<span>你好</span>
@Html.Br()
<span>朋友</span>
<Hello id="1001" name="wd" age="18"></Hello>
</div>
</body>
</html>
最后还需注册标记:如下图所示
结果
成功渲染成div标签
局部视图
新建一个视图
在另一个视图中通过Html.Partial("Viewts")
调用
@Html.Partial("Viewts","00000")//还可以传递参数
@model string
<h1 style="background-color:pink">实例东风科技sad家乐福:@Model</h1>
IOC容器IServiceCollection
什么IOC?
把对象的创建统一交给第三方容器来创见;
如何使用内置IOCIServiceCollection:
首先新建两个类库Interface、Service,接口与类一一对应
第一种:
- 在Startup中的ConfigureServices 方法中注册服务
services.AddTransient<IServiceA, ServiceA>();
- 在需要使用的控制器中,通过构造函数,定义服务的抽象类型,作为参数,在运行时,自动得到服务的具体
private readonly IServiceA _IServicA = null;
public FifthController(IServiceA iServicA)
{
_IServicA = iServicA;
}
- 调用服务内部的方法
public IActionResult Index()
{
_IServicA.Show(); //调用接口中的方法
return View();
}
第二种:
第一二步跟上面一样
- 3.通过_ServiceProvider获取到服务,然后通过服务实例调用服务内部的方法
public IActionResult Index()
{
IServiceA ServiceA = (IServiceA)_ServiceProvider.GetService(typeof(IServiceA));
ServiceA.Show();
}
第三种:
在注册服务后,视图中通过关键字@Inject 获取实例
@inject IServiceA iServicA ---获取到服务实例
@{
iTestServicA.Show();
}
DI依赖注入:IServiceCollection支持且仅支持构造函数注入
什么是依赖注入?
如果对象A依赖于对象B,对象B依赖于对象C,就可以先构造对象C,然后传递给对象B,然后把对象B传递给对象A,得到A的具体实例;
IServiceCollection可以支持无线层级的以来注入; 前提是都要先注入服务(注册抽象和具体的映射关系)
IServiceCollection生命周期
那么在创建对象的时候,不同的情况,需要让对象单利,每一次都创建新的对象实例;不同的作用于创
建新的实例;
瞬时生命周期:每一次getService获取的实例都是不同的实例
单例生命周期,在整个进程中获取的都是同一个实例
作用域生命周期;同一个作用域,获取的是同一个对象的实例;不同的作用域,获取的是不同的对象实
例
建议:开发工作中,一般情况下,都是一起请求一个对象的实例;更多的是瞬时生命周期的使用;
//瞬时生命周期
{
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<ITestServiceA, TestServiceA>(); 瞬时生命周期,每一次getService获取的实例都是不同的实例
ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
IServiceA ServiceA = serviceProvider.GetService<IServiceA>();
IServiceA ServiceA1 = serviceProvider.GetService<IServiceA>();
bool isOK = object.ReferenceEquals(ServiceA, ServiceA1); 结果为false; 两次获取的对象不是同一个实例
}
//单例生命周期
{
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IServiceA, ServiceA>(); 单例生命周期,在整个进程中获取的都是同一个实例
ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
IServiceA ServiceA = serviceProvider.GetService<IServiceA>();
IServiceA ServiceA1 = serviceProvider.GetService<ITestServiceA>();
bool isOK = object.ReferenceEquals(ServiceA, ServiceA1); 结果为 true,是同一个引用,在整个进程中获取的都是同一个实例
}
//作用域生命周期
{
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<IServiceA, ServiceA>(); //作用域生命周期;同一个作用域,获取的是同一个对象的实例;不同的作用域,获取的是不同的对象实例
ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
IServiceA ServiceA = serviceProvider.GetService<IServiceA>();
IServiceA ServiceA1 = serviceProvider.GetService<ITServiceA>();
bool isOK = object.ReferenceEquals(ServiceA, ServiceA1);
ServiceProvider serviceProvider1 = serviceCollection.BuildServiceProvider();
IServiceA ServiceA2 = serviceProvider1.GetService<IServiceA>();
bool isOK1 = object.ReferenceEquals(ServiceA1, ServiceA2);
}
Autofa容器
Autofa也是一款很流行的IOC容器:第三方的IOC容器
- Nuget引入程序包: Autofa
- 创建一个ContainerBuilder
- 注册抽象和实现关系
- Build一下,得到IContainer容器
- 通过容器获取服务实例
- 使用服务
构造函数注入
//构造函数注入
ContainerBuilder containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<TestServiceA>().As<ITestServiceA>();
containerBuilder.RegisterType<TestServiceB>().As<ITestServiceB>();
containerBuilder.RegisterType<TestServiceC>().As<ITestServiceC>();
IContainer container = containerBuilder.Build();
ITestServiceC testServiceC = container.Resolve<ITestServiceC>();//获取服务
testServiceC.Show();
属性注入
ContainerBuilder containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<TestServiceA>().As<ITestServiceA>();
containerBuilder.RegisterType<TestServiceB>().As<ITestServiceB>();
containerBuilder.RegisterType<TestServiceC>().As<ITestServiceC>();
containerBuilder.RegisterType<TestServiceD>().As<ITestServiceD>().PropertiesAutowired();
IContainer container = containerBuilder.Build();
ITestServiceD testServiceD = container.Resolve<ITestServiceD>();//获取服务
testServiceD.Show();
using ITestService;
using System;
namespace TestService
{
public class TestServiceD : ITestServiceD
{
public string strin { get; set; }
public ITestServiceA _iTestServiceA { get; set; }
public ITestServiceB _iTestServiceB { get; set; }
public ITestServiceC _iTestServiceC { get; set; }
public TestServiceD()
{
Console.WriteLine($"{this.GetType().Name}被构造");
}
public void Show()
{
_iTestServiceA.Show();
Console.WriteLine("000000000");
}
}
}
方法注入
ContainerBuilder containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<TestServiceA>().As<ITestServiceA>();
containerBuilder.RegisterType<TestServiceC>().As<ITestServiceC>();
containerBuilder.RegisterType<TestServiceD>().As<ITestServiceD>().PropertiesAutowired();
containerBuilder.RegisterType<TestServiceB>().OnActivated(e =>
e.Instance.SetService(e.Context.Resolve<ITestServiceA>())).As<ITestServiceB>();
IContainer container = containerBuilder.Build();
ITestServiceB testServiceB = container.Resolve<ITestServiceB>();//获取服务
testServiceB.Show();
using ITestService;
using System;
namespace TestService
{
public class TestServiceB : ITestServiceB
{
public ITestServiceA _iTestServiceA = null;
public void SetService(ITestServiceA iTestServiceA)
{
_iTestServiceA = iTestServiceA;
}
public TestServiceB(ITestServiceA iTestServiceA)
{
Console.WriteLine($"{this.GetType().Name}被构造");
}
public void Show()
{
//_iTestServiceA.Show();
Console.WriteLine($"bbb");
}
}
}
Autofa 生命周期
//生命周期
//瞬时生命
//ContainerBuilder containerBuilder = new ContainerBuilder();
//containerBuilder.RegisterType<TestServiceA>().As<ITestServiceA>().InstancePerDependency();
//IContainer container = containerBuilder.Build();
//ITestServiceA testServiceA = container.Resolve<ITestServiceA>();//获取服务
//ITestServiceA testServiceA1 = container.Resolve<ITestServiceA>();//获取服务
//bool a = object.ReferenceEquals(testServiceA, testServiceA1);
//Console.WriteLine(object.ReferenceEquals(testServiceA, testServiceA1));//false
//单例生命
//ContainerBuilder containerBuilder = new ContainerBuilder();
//containerBuilder.RegisterType<TestServiceA>().As<ITestServiceA>().SingleInstance();
//IContainer container = containerBuilder.Build();
//ITestServiceA testServiceA = container.Resolve<ITestServiceA>();//获取服务
//ITestServiceA testServiceA1 = container.Resolve<ITestServiceA>();//获取服务
//bool a = object.ReferenceEquals(testServiceA, testServiceA1); //true
//范围生命
//ContainerBuilder containerBuilder = new ContainerBuilder();
//containerBuilder.RegisterType<TestServiceA>().As<ITestServiceA>().InstancePerLifetimeScope();
//IContainer container = containerBuilder.Build();
//ITestServiceA testServiceA15 = null;
//ITestServiceA testServiceA16 = null;
//using (var scope1 = container.BeginLifetimeScope())
//{
// ITestServiceA testServiceA11 = scope1.Resolve<ITestServiceA>();
// ITestServiceA testServiceA12 = scope1.Resolve<ITestServiceA>();
// Console.WriteLine(object.ReferenceEquals(testServiceA11, testServiceA12)); //true
// testServiceA15 = testServiceA12;
//}
//using (var scope1 = container.BeginLifetimeScope())
//{
// ITestServiceA testServiceA13 = scope1.Resolve<ITestServiceA>();
// ITestServiceA testServiceA14 = scope1.Resolve<ITestServiceA>();
// Console.WriteLine(object.ReferenceEquals(testServiceA13, testServiceA14)); //true
// testServiceA16 = testServiceA14;
//}
//Console.WriteLine(object.ReferenceEquals(testServiceA15, testServiceA16)); //false
//匹配生命范围一个实例
//ContainerBuilder containerBuilder = new ContainerBuilder();
//containerBuilder.RegisterType<TestServiceA>().As<ITestServiceA>
//().InstancePerMatchingLifetimeScope("XXX"); //匹配范围,在该名称范围里面全部是同一个实例
//IContainer container = containerBuilder.Build();
//ITestServiceA testServiceA15 = null;
//ITestServiceA testServiceA16 = null;
//using (var scope1 = container.BeginLifetimeScope("XXX"))
//{
// ITestServiceA testServiceA11 = scope1.Resolve<ITestServiceA>();
// using (var scope2 = scope1.BeginLifetimeScope())
// {
// ITestServiceA testServiceA12 = scope2.Resolve<ITestServiceA>();
// Console.WriteLine(object.ReferenceEquals(testServiceA11, testServiceA12)); //true
// }
// testServiceA15 = testServiceA11;
//}
//using (var scope1 = container.BeginLifetimeScope("XXX"))
//{
// ITestServiceA testServiceA13 = scope1.Resolve<ITestServiceA>();
// using (var scope2 = scope1.BeginLifetimeScope())
// {
// ITestServiceA testServiceA14 = scope2.Resolve<ITestServiceA>();
// Console.WriteLine(object.ReferenceEquals(testServiceA13, testServiceA14)); //true
// }
// testServiceA16 = testServiceA13;
//}
//Console.WriteLine(object.ReferenceEquals(testServiceA15, testServiceA16)); //false
Autofac支持配置文件
- Nuget引入程序集:
Autofac.Extensions.DependencyInjection
Autofac.Configuration
Autofac - 准备配置文件
- 读取配置文件,根据配置文件信息,生成抽象和映射信息
新建的配置文件 autofac.json:
{
"components": [
{
"type": "TestService.TestServiceA,TestService",
"services": [
{
"type": "ITestService.ITestServiceA,ITestService"
}
],
"instanceScope": "single-instance", //生命周期
"injectProperties": true // 属性注入
},
{
"type": "TestService.TestServiceB,TestService",
"services": [
{
"type": "ITestService.ITestServiceB,ITestService"
}
],
"instanceScope": "single-instance", //生命周期
"injectProperties": true // 属性注入
},
{
"type": "TestService.TestServiceC,TestService",
"services": [
{
"type": "ITestService.ITestServiceC,ITestService"
}
],
"instanceScope": "single-instance", //生命周期
"injectProperties": true // 属性注入
},
{
"type": "TestService.TestServiceD,TestService",
"services": [
{
"type": "ITestService.ITestServiceD,ITestService"
}
],
"instanceScope": "single-instance", //生命周期
"injectProperties": true // 属性注入
},
{
"type": "TestService.TestServiceE,TestService",
"services": [
{
"type": "ITestService.ITestServiceE,ITestService"
}
],
"instanceScope": "single-instance", //生命周期
"injectProperties": true // 属性注入
}
]
}
//Autofac 支持配置文件
ContainerBuilder containerBuilder = new ContainerBuilder();
// 就可以在这里写入Autofac注入的各种
{
//读取配置文件,把配置关系装载到ContainerBuilder
IConfigurationBuilder config = new ConfigurationBuilder();
IConfigurationSource autofacJsonConfigSource = new JsonConfigurationSource()
{
Path = "autofac.json", //文件所在路径 我的是放在根目录下
Optional = false,//boolean,默认就是false,可不写
ReloadOnChange = true,//同上
};
config.Add(autofacJsonConfigSource);
ConfigurationModule module = new ConfigurationModule(config.Build());
containerBuilder.RegisterModule(module);
}
IContainer container = containerBuilder.Build();
ITestServiceA testServiceA = container.Resolve<ITestServiceA>();
ITestServiceD testServiceD = container.Resolve<ITestServiceD>();
testServiceD.Show();
Autofac整合.NET5 MVC
- 指定Autofac工厂替换默认工厂,Program指定
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseServiceProviderFactory(new AutofacServiceProviderFactory());
- 在Startup类增加ConfigureContainer 方法, 注册关系
//Autofac 整合mvc Program中配置好后会在startup中自动执行此方法
public void ConfigureContainer(ContainerBuilder builder)
{
//注册服务
builder.RegisterType<TestServiceA>().As<ITestServiceA>();
builder.RegisterType<TestServiceB>().As<ITestServiceB>();
builder.RegisterType<TestServiceC>().As<ITestServiceC>();
builder.RegisterType<TestServiceD>().As<ITestServiceD>().PropertiesAutowired(); //在TestServiceD里也支持属性注入
builder.RegisterType<TestServiceE>().As<ITestServiceE>();
}
- 通过控制器构造函数注入,获取实例
using ITestService;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebApplication6.Controllers
{
public class TrwoController : Controller
{
private readonly ITestServiceA _ITestServicA = null;
private readonly ITestServiceB _ITestServicB = null;
private readonly ITestServiceD _ITestServicD = null;
public TrwoController(ITestServiceA iTestServicA, ITestServiceD iTestServicD,
ITestServiceB iTestServicB)
{
_ITestServicA = iTestServicA;
_ITestServicB = iTestServicB;
_ITestServicD = iTestServicD;
}
public IActionResult Index()
{
_ITestServicD.Show();
return View();
}
}
}
ServiceCollection注册的服务也可以让Autofac使用,因为Autofac在自己注册服务之前;会先把ServiceCollection中注册的服务全部接管过来;
services.AddTransient<ITestServiceA, TestServiceA>();
services.AddTransient<ITestServiceB, TestServiceB>();
通过内置IOC容器注册的服务Autofac也可以接管过来进行使用。
Autofac让控制器支持属性注入
控制器是一个类,控制器的实例其实是IControllerActivator来创建的;
1.得让控制器使用容器来获取实例;
2.注册控制器抽象和具体的关系
var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes()
.Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired(new AutowiredPropertySelector());
3.在控制器内定义属性
4.扩展,自己控制究竟哪些属性需要做依赖注入
需要新建两个类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebApplication6.Unity
{
[AttributeUsage(AttributeTargets.Property)]
public class CustomPropertyAttribute : Attribute
{
}
}
using Autofac.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace WebApplication6.Unity
{
public class CustomPropertySelector : IPropertySelector
{
public bool InjectProperty(PropertyInfo propertyInfo, object instance)
{
//需要一个判断的维度;
return propertyInfo.CustomAttributes.Any(it => it.AttributeType == typeof(CustomPropertyAttribute));
}
}
}
Autofac抽象多实现的问题
1.一个抽象多个实例,都注册了,通过构造函数用抽象类型来获取实例,哪个后面注册就获取到哪一个;覆盖型;
2.一个抽象多个实例,都注册了,可以通过一个IEnumerable<抽象>,当做构造函数参数,可以获取到所有注册的具体的实例;
3.注册一个抽象的多个实例资源,如下方式注册,可以在控制器的构造函数中,使用具体实现类型作为参数类型,可以匹配到不同到具体类型实例
首先新建一个工具类
using Autofac;
using Autofac.Features.ResolveAnything;
using ITestService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebApplication6.Unity
{
public class AutofacModule: Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(t => t.IsAssignableTo<ITestServiceA>()));
}
}
}
ConfigureContainer方法中添加
//单抽象多实现
builder.RegisterType<TestServiceA>().As<ITestServiceA>();
builder.RegisterType<TestServiceA>().As<ITestServiceA>();
builder.RegisterType<TestServiceA>().As<ITestServiceA>();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(t => t.IsAssignableTo<ITestServiceA>()));
builder.RegisterModule(new AutofacModule());
builder.RegisterModule<AutofacModule>();
最后到控制器中测试
using ITestService;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TestService;
using WebApplication6.Unity;
namespace WebApplication6.Controllers
{
public class TrwoController : Controller
{
private readonly ITestServiceA _ITestServicA = null;
private readonly TestServiceA testServiceA = null; //可以获取到接口的实现类
//private readonly ITestServiceB _ITestServicB = null;
//private readonly ITestServiceD _ITestServicD = null;
private readonly IEnumerable<ITestServiceA> _ITestServicAlist = null;
[CustomPropertyAttribute]
private ITestServiceD testServiceD { get; set; }
public TrwoController(ITestServiceA iTestServicA,
IEnumerable<ITestServiceA> ITestServicAlist, TestServiceA testServiceA)
{
this.testServiceA = testServiceA;
_ITestServicAlist = ITestServicAlist;
_ITestServicA = iTestServicA;
}
public IActionResult Index()
{
// testServiceD.Show();
return View();
}
}
}
Autofac支持AOP
AOP面向切面编程;不用修改之前代码的基础上,可以动态的在某个动作之前加一些操作,动态在在某一个动作之后做点什么事儿
- Nuget引入Castle.Core程序集+Autofac.Extras.DynamicProxy程序集
在ConfigureContainer方法中添加
builder.RegisterType(typeof(CustomAutofacAop));
builder.RegisterType<TestServiceA1>().As<ITestServiceA>().EnableInterfaceInterceptors();//表示接口类型的切入编程
在接口上标记[Intercept(typeof(CustomAutofacAop))]
using AopComm;
using Autofac.Extras.DynamicProxy;
using System;
namespace ITestService
{
[Intercept(typeof(CustomAutofacAop))] //AOP能够在当前接口生效
public interface ITestServiceA
{
void Show();
}
}
创建一个类CustomAutofacAop 此类继承IInterceptor
using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Text;
namespace AopComm
{
public class CustomAutofacAop : IInterceptor
{
public void Intercept(IInvocation invocation)
{
{
Console.WriteLine("方法执行前");
}
invocation.Proceed();//执行这句话就是去执行具体的实例的这个方法
{
Console.WriteLine("方法执行后");
}
}
}
}
在控制器中测试
using ITestService;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TestService;
using WebApplication6.Unity;
namespace WebApplication6.Controllers
{
public class TrwoController : Controller
{
private readonly ITestServiceA _ITestServicA = null;
//private readonly TestServiceA testServiceA = null;
//private readonly ITestServiceB _ITestServicB = null;
//private readonly ITestServiceD _ITestServicD = null;
private readonly IEnumerable<ITestServiceA> _ITestServicAlist = null;
[CustomPropertyAttribute]
ITestServiceD testServiceD { get; set; }
public TrwoController(ITestServiceA iTestServicA,
IEnumerable<ITestServiceA> ITestServicAlist)
{
_ITestServicAlist = ITestServicAlist;
_ITestServicA = iTestServicA;
}
public IActionResult Index()
{
_ITestServicA.Show();//在执行此方法之前会去CustomAutofacAop 中执行Intercept方法
return View();
}
}
}
Autofac 通过类支持AOP
builder.RegisterType(typeof(CustomAutofacAop));
builder.RegisterType<TestServiceA>().As<ITestServiceA>().EnableClassInterceptors(); //实现类
在实现类中标记
using AopComm;
using Autofac.Extras.DynamicProxy;
using ITestService;
using System;
namespace TestService
{
[Intercept(typeof(CustomAutofacAop))]
public class TestServiceA : ITestServiceA
{
public TestServiceA()
{
Console.WriteLine($"{this.GetType().Name}被构造。。。");
}
public virtual void Show()
{
Console.WriteLine("AAAA");
}
}
}
注意, 如果同过类切入编程,在调用该类中的方法时,该方法必须是虚方法
virtual
Autofac单抽象多实现构造函数注入
- 注册的时候可以指定一个标识
containerBuilder.RegisterType<TestServiceA>().Named<ITestServiceA>("TestServiceA");
containerBuilder.RegisterType<TestServiceUpdate>().Named<ITestServiceA>("TestServiceUpdate");
- 在控制器中获取的时候获取一个Autofac的上下文,通过上下文+标识,得到不同的实现的实例
private readonly IComponentContext _ComponentContext = null;
public TrwoController(IComponentContext componentContext)
{
_ComponentContext = componentContext;
}
public IActionResult Index()
{
ITestServiceA testServiceA = _ComponentContext.ResolveNamed<ITestServiceA>
("TestServiceA");
ITestServiceA testServiceUpdate = _ComponentContext.ResolveNamed<ITestServiceA>
("TestServiceUpdate");
return View();
}
.NET5 AOP 5个Filter
Filter的作用是在Action 执行前或执行后做一些加工处理。
- Authorization Filter
Authorization是五种Filter中优先级最高的,通常用于验证Request合不合法,不合法后面就直接跳过,鉴权授权。 - Resource Filter
Resource是第二优先,会在Authorization之后,Model Binding之前执行。就是为了缓存而存在。 - Action Filter
最常使用的Filter,封包进出都会经过它,使用上没什么需要特别注意的。跟Resource Filter很类似,但并不会经过Model Binding。 - Exception Filter
异常处理的Filter。 - Result Filter
当Action完成后,最终会经过的Filter。
ActionFilter
自定义一个CustomActionFilterAttribute特性,继承Attribute,实现IActionFilter接口;实现方法,标记在Action上;
请求标记的有CustomActionFilterAttribute 的Action:执行顺序如下:
- 执行控制器构造函数
- 执行CustomActionFilterAttribute 内的OnActionExecuting方法
- 执行Action
- 执行CustomActionFilterAttribute 内的OnActionExecuted
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Zhaoxi.NET5Demo.Project.Utility.Filters
{
public class CustomActionFilterAttribute : Attribute, IActionFilter
{
public ILogger<CustomActionFilterAttribute> _iLoggerProp { get; set; }
private ILogger<CustomActionFilterAttribute> _iLogger = null;
public CustomActionFilterAttribute(ILogger<CustomActionFilterAttribute> logger)
{
_iLogger = logger;
}
/// <summary>
/// 方法执行前
/// </summary>
/// <param name="context"></param>
public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ActionDescriptor.EndpointMetadata.Any(item=>item.GetType()==typeof(CustomAllowAnonymousAttribute))) //如果标记的有特殊的记号,就避开检查;
{
return;
}
_iLoggerProp.LogInformation("支持属性注入");
///记录请求来了之后的一些参数:
//参数 Newtonsoft.Json.JsonConvert.SerializeObject(context.HttpContext.Request.Query)
//log4net;
_iLogger.LogInformation(Newtonsoft.Json.JsonConvert.SerializeObject(context.HttpContext.Request.Query));
_iLogger.LogInformation("CustomActionFilterAttribute.OnActionExecuting");
}
/// <summary>
/// 方法执行后
/// </summary>
/// <param name="context"></param>
public void OnActionExecuted(ActionExecutedContext context)
{
_iLogger.LogInformation(Newtonsoft.Json.JsonConvert.SerializeObject(context.Result));
_iLogger.LogInformation("CustomActionFilterAttribute.OnActionExecuted");
}
}
public class CustomActionFilterChildAttribute : ActionFilterAttribute
{
/// <summary>
/// 方法执行前
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
}
/// <summary>
/// 方法执行后
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
}
}
public class CustomActionFilterAsyncAttribute : Attribute, IAsyncActionFilter
{
/// <summary>
/// 异步版本
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
return Task.Run(() =>
{
});
}
}
}
Filter的多种注册
1.[CustomActionFilter]—Fitler必须有无参数构造函数
2.[TypeFilter(typeof(CustomActionFilterAttribute))],可以没有无参数构造函数,可以支持依赖注入
3.[ServiceFilter(typeof(CustomActionFilterAttribute))],可以没有无参数构造函数,可以支持依赖注
入,但是必须要注册服务
//支持Filter属性依赖注入
builder.RegisterType(typeof(CustomActionFilterAttribute)).PropertiesAutowired();
//[CustomActionFilterAttribute] //必须含有无参构造
//[TypeFilter(typeof(CustomActionFilterAttribute))] //支持构造函数注入 参数
[ServiceFilter(typeof(CustomActionFilterAttribute))] // 即支持构造函数又支持属性 参数
public IActionResult Index()
{
_ITestServicA.Show();
return View();
}