关于asp.netcore mvc(从入门到精通)

MVC开发

  1. 什么是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,接口与类一一对应

第一种:

  1. 在Startup中的ConfigureServices 方法中注册服务
services.AddTransient<IServiceA, ServiceA>();
  1. 在需要使用的控制器中,通过构造函数,定义服务的抽象类型,作为参数,在运行时,自动得到服务的具体
private readonly IServiceA _IServicA = null;
 public FifthController(IServiceA iServicA)
 {
           _IServicA = iServicA; 
 }
  1. 调用服务内部的方法
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容器

  1. Nuget引入程序包: Autofa
  2. 创建一个ContainerBuilder
  3. 注册抽象和实现关系
  4. Build一下,得到IContainer容器
  5. 通过容器获取服务实例
  6. 使用服务

构造函数注入

                //构造函数注入
                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支持配置文件

  1. Nuget引入程序集:
    Autofac.Extensions.DependencyInjection
    Autofac.Configuration
    Autofac
  2. 准备配置文件
  3. 读取配置文件,根据配置文件信息,生成抽象和映射信息

新建的配置文件 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

  1. 指定Autofac工厂替换默认工厂,Program指定
public static IHostBuilder CreateHostBuilder(string[] args) =>
           Host.CreateDefaultBuilder(args) 
               .ConfigureWebHostDefaults(webBuilder =>
               {
                   webBuilder.UseStartup<Startup>();
               })
               .UseServiceProviderFactory(new AutofacServiceProviderFactory());
  1. 在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>();
        }
  1. 通过控制器构造函数注入,获取实例
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面向切面编程;不用修改之前代码的基础上,可以动态的在某个动作之前加一些操作,动态在在某一个动作之后做点什么事儿

  1. 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单抽象多实现构造函数注入

  1. 注册的时候可以指定一个标识
containerBuilder.RegisterType<TestServiceA>().Named<ITestServiceA>("TestServiceA");
containerBuilder.RegisterType<TestServiceUpdate>().Named<ITestServiceA>("TestServiceUpdate");
  1. 在控制器中获取的时候获取一个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:执行顺序如下:

  1. 执行控制器构造函数
  2. 执行CustomActionFilterAttribute 内的OnActionExecuting方法
  3. 执行Action
  4. 执行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();
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值