使用Code First建模自引用关系笔记 asp.net core上使用redis探索(1) asp.net mvc控制器激活全分析 语言入门必学的基础知识你还记得么? 反射

时间:2023-11-22 15:22:14

使用Code First建模自引用关系笔记

原文链接

一.Has方法:

A.HasRequired(a => a.B);
  1. HasOptional:前者包含后者一个实例或者为null
  2. HasRequired:前者(A)包含后者(B)一个不为null的实例
  3. HasMany:前者包含后者实例的集合

二.With方法:

A.HasRequired(a => a.B);
  1. WithOptional:后者(B)可以包含前者(A)一个实例或者null
  2. WithRequired:后者包含前者一个不为null的实例
  3. WithMany:后者包含前者实例的集合

asp.net core上使用redis探索(1)

基于Ubuntu安装redis, 我找的一个很好的网站: 
https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-redis-on-ubuntu-16-04
设置redis密码登录, 编辑redis.conf文件:
将requirepass 后面数据改为你想要的密码。

将redis设置为远程可访问, 编辑redis.conf文件:
将bind 127.0.0.1 改为 bind 0.0.0.0

以上是redis本身的配置,下面我来介绍下如何在.net-core上部署并使用redis,以前基于.NET的时候使用的是ServiceStack.Redis来作为驱动,该驱动有在.net-core上使用的版本,但是目前微软官方就提供了基于Redis的分布式存储,就内嵌在.net core里面具体请看:
https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/distributed
可以下载官方示例,我没有使用它。跑了一遍代码,没有成功,就放弃了(而且这个实现太简单了),微软官方还有这个示例,挺好的,我做了参考,虽然也没有应用它, 代码地址:
https://github.com/aspnet/Caching/tree/dev/src/Microsoft.Extensions.Caching.Redis
这个还是可以的,很好,可以看看。
而后,我在网上找到这篇文章,介绍的很好,设计思路也很不错,但是跑起来的时候失败了,不过也是收获很多, 地址:
https://zablo.net/blog/post/asp-net-core-redis-html-cache
随后我找到了一篇很好的实现,代码地址:
https://github.com/jakeuj/Microsoft.Extensions.Caching.Redis
这个的实现是基于Microsoft.Extensions.Caching.Redis(微软自己的redis实现)。还是很好的,作者自己封装了很多,照着打了遍代码,然后再结合上面第3个链接的代码,自己做了点修改,主要还是在Redis的存储函数Set那,多的修改没有做。总算是成功的跑起来了,随后再深入研究下具体的实现,同时结合微软的官方实现来做些自己的修改。
一开始查资料的时候,我算是见识到了。百度出来的东西那是千篇一律,最后直接用bing搜,还是Bing良心点,真是不知道一篇文章被好几十个人转有什么意思,而且原文的实现还是有问题的。网络风气啊....

等自己结合上面的几个链接重新封装下redis的类库,再把代码放上来。

asp.net mvc控制器激活全分析

控制器的激活默认情况下使用反射来实现的,这其中采用了DI,单例等设计模式。对于控制器的主要涉及到如下的类:
ControllerBuilder、DefaultControllerFactory、DefaultControllerActivator(实现了IControllerActivator接口)、DependencyResolver(并没有实现IDependencyResolver,但是有这个接口对象实例)、DefaultDependencyResolver(实现了IDependencyResolver接口,默认采用此类来解析控制器对象)

如上的几个类是控制器激活最重要的类。大概说说过程,备忘,当然也说不了多具体,有个大概思路就好,网上已经很多介绍的文章了。DefaultControllerFactory并不是构造控制器的地方,控制器的构造实在ControllerBuilder中,具体涉及到SetControllerFactory以及GetControllerFactory两个方法,我们可以通过SetControllerFactory来拓展自己的IOC容器,这是第一个可供拓展点。
DefaultControllerActivator类用来激活控制器,我们一般创建自己的MVC框架的时候,都是在这个类实现的ICOntrollerActivator接口的Create方法中,通过获取的控制器对象使用反射来创建控制器实例。当然这是在我们自己创建自己的MVC框架以及不使用第三方IOC容器的时候,就是使用该方法来创建的,而在MVC框架中,控制器实例的创建是延迟到了efaultDependencyResolver类中。这也是第二个可拓展的地方,我们可以在第三方IOC容器中,实现IControllerActivator接口来创建控制器对象。
DefaultDependencyResolver类实现了IDependencyResolver接口,默认的MVC框架实现的IOC容器(基于DI模式)设计的容器。我们就是在这里构造了我们的IOC容器,不过通过阅读源码你会发现,该IOC容器源码其实就是默认使用反射来创建控制器对象。这与上面的DefaultControllerActivator类的作用是一样的。可以参考源码:

使用Code First建模自引用关系笔记    asp.net core上使用redis探索(1)    asp.net mvc控制器激活全分析   语言入门必学的基础知识你还记得么?    反射
public IController Create(RequestContext requestContext, Type controllerType)
            {
                try
                {
                    return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
                }
                catch (Exception ex)
                {
                    throw new InvalidOperationException(
                        String.Format(
                            CultureInfo.CurrentCulture,
                            MvcResources.DefaultControllerFactory_ErrorCreatingController,
                            controllerType),
                        ex);
                }
            }
使用Code First建模自引用关系笔记    asp.net core上使用redis探索(1)    asp.net mvc控制器激活全分析   语言入门必学的基础知识你还记得么?    反射

可以看到上面的try语句里面的代码,通过调用GetService()方法,默认使用MVC自己的IOC容器(即DefaultDependencyResolver类)。在这里我们可以基于第三方的IOC来拓展我们自己的设计逻辑,这也是第三个可拓展点。

<<asp.net mvc5框架揭秘>>一书中详细说了三个可拓展的地方就是如上的描述。上面的描述就是我自己看源码以及资料的一个总结,当你看MVC源码的时候,你会有自己的收获,我也没有全部铺开来,仅仅就是自己的心得笔记。

语言入门必学的基础知识你还记得么?

不管我们学习什么语言,一开始都是语法,对于面向对象的语言来讲,学习完语法之后,就是OOP了,主要还是三大概念:继承,多态,封装。而且我们经常也会遇到一些面试题,会考察我们父子类之间的继承关系等。

这段时间深造ASP.NET-MVC框架,研读<<asp.net-mvc框架揭秘>>一书的时候,感觉到了自己的不足与渺小。尽管大三就看过这本书,但那时候看的懵逼,半知半解吧。再过了差不多一年之后再回头看这本书,学到了不同的知识,也看到了不同的一面,这说明自己也是在逐步提升的。这两天研读Controller激活原理的时候,深入的思考了一下,下载了源码看,发现看的很是懵逼啊,<<揭秘>>一书尽管一开始就写了个简单地mvc框架,但是相比较于源码中的代码还是缩减了很多,不过我看源码还是看的很懵逼,主要还是各个类之间的实现以及解耦的设计太好了,有一部分我特别不懂,于是自己写了个demo分析,分析完之后发现原来就是父子类之间的继承关系而已,以及C#特有的委托特性。不多说,直接上我的demo:

使用Code First建模自引用关系笔记    asp.net core上使用redis探索(1)    asp.net mvc控制器激活全分析   语言入门必学的基础知识你还记得么?    反射
using System;

namespace ConsoleApp1
{
    public class MyTest2
    {
        public MyTest2(Func<string> func)
        {
            if(func==null)
            {
                throw new ArgumentNullException("error ... ");
            }
            func();
            Console.WriteLine("successful ... ");
        }
    }

    public class MyTest
    {
        public Func<string> _func = () => null;

        private static MyTest _instance = new MyTest();

        public MyTest() : this(null)
        {
            Console.WriteLine("Construction .... ");
        }

        public MyTest(MyTest2 s)
        {
            MyTest2 _s = s ?? new MyTest2(_func);
        }

        public static MyTest Current
        {
            get { return _instance; }
        }

        public static string text
        {
            get { return "text .... "; }
        }

        public void Beta()
        {
            Console.WriteLine("function be called");
        }

        public static string Func_Test()
        {
            return null;
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            MyTest.Current.Beta();

            Console.Read();
        }
    }
}
使用Code First建模自引用关系笔记    asp.net core上使用redis探索(1)    asp.net mvc控制器激活全分析   语言入门必学的基础知识你还记得么?    反射

我一开始就看不懂在_func属性明明就是返回来了null,在MyTest2中的if判断应该成立啊,后来断点调试看了下:
使用Code First建模自引用关系笔记    asp.net core上使用redis探索(1)    asp.net mvc控制器激活全分析   语言入门必学的基础知识你还记得么?    反射

这是内存地址啊,后来我改了下:

public Func<string> _func = () => null;

改成了:

public Func<string> _func = Func_Test;

后来才反应过来,原来传递的参数根本就是一个函数地址而已,if中的null是用来判断是不是没有传参的。

其次就是构造函数了,我已开始比较纳闷MyTest的第二个构造函数是怎么调用的,后来想想原来是第一个构造函数继承自了this(null),引发了调用!

通过这个demo也算是让自己巩固了基础吧。

反射

文本较差,具体请看代码,如有错误,欢迎指出

1.反射生成类步骤:
加载DLL(【Assembly】.Load,LoadFile,LoadFrom),LoadFrom实质上也是调用Load,但是可以指定全路径
获取格式
实例化
object DB=Activator.CreateInstance(Tp);【属于Object类,无法调用方法】
[类型] ODB=(类型)DB;【需要强制转换后才可以使用】

2.调用方法
  4.1 构造函数:

object DB=Activator.CreateInstance(Tp);
  4.1.1 调用私有构造函数:
  object DB=Activator.CreateInstance(Tp,true);

4.1.2 生成泛型构造函数:若反射的类为DBHelper<T,W,X>,则
Type Tp=As.GetType("ConsoleApp1.SayHello`2");【包含2个占位符,需要写入】
Type NewTp=Tp.MakeGenericType(typeof(string), typeof(int));【重新生成一个新的类型,需要将类型赋给泛型然后生成该新的类型】
object DB=Activator.CreateInstance(NewTp);【使用新类型创建对象】

4.1.3 调用有参数的构造函数:构造函数为DBHelper(int x,string y){};DBHelper(string X){};【两个构造函数】
Assembly As=Assembly.Load("Ruanmou.DB.Sqlserver");
Type Tp=As.GetType("Ruanmou.DB.Sqlserver.DBHelper");
object DB1=Activator.CreateInstance(Tp,new object{223,"Abc"});【传递参数调用对应的构造函数,会根据传递的参数的类型调用对应的构造函数】
object DB2=Activator.CreateInstance(Tp,new object{"Abc"});【传递的参数必须跟已经有的构造函数的位置和类型一致,否则会报错】、

4.2 方法:(DB1 是已经实例化的类,且未强制转换的Object类型 Tp为获取的类型)
4.2.1 无参数实例化方法 :Show1(){};
MethodInfo method=Tp.GetMethod("Show1");
method.Invoke(DB1,null);

4.2.2 有参数实例化方法 :Show2(int x){};
MethodInfo method=Tp.GetMethod("Show2");
method.Invoke(DB1,new object{123});

4.2.3 有参数静态方法 :static Show3(int x){};
MethodInfo method=Tp.GetMethod("Show3");
method.Invoke(null,new object{123});【可以传递实例,但是不会调用】

4.2.3 多个重载方法 : Show4(){};Show4(int x){};Show4(string y){};Show4(int x,string y){};Show4(string y,int x){};
MethodInfo method1=Tp.GetMethod("Show3",new Type{});【调用无参重载】
MethodInfo method2=Tp.GetMethod("Show3",new Type{typeof(int)});【调用带一个Int重载】
MethodInfo method3=Tp.GetMethod("Show3",new Type{typeof(string)});
MethodInfo method4=Tp.GetMethod("Show3",new Type{typeof(int),typeof(string)});
MethodInfo method5=Tp.GetMethod("Show3",new Type{typeof(string),typeof(int)});

method1.Invoke(DB1);【无参数不必传递参数】
method2.Invoke(DB1,new object{123});【有参数的必须传递对应参数】
method3.Invoke(DB1,new object{"abc"});【】
method4.Invoke(DB1,new object{123,"abc"});【参数的类型,位置都必须一致】
method5.Invoke(DB1,new object{"abc",123});【】

4.2.4 调用私有方法: Private Show5 (){};
MethodInfo method=Tp.GetMethod("Show5",BingDingFlags.NonPublic|BingDingFlags.Instance);【获取私有属性必须两个都写上】
method.Invoke(DB1);

4.2.5 调用泛型方法: Show6<T>(T a){};
MethodInfo method=Tp.GetMethod("Show6");
Newmethod = method.MakeGenericMethod(typeof(string));【设置泛型为string】
Newmethod.Invoke(DB1,new object{"abc"});

4.3 属性和字段
4.3.1 获取和设置属性(DB1 是已经实例化的类,且未强制转换的Object类型 Tp为获取的类型)
foreach(var item in Tp.GetProperties())
{
item.GetValue();
if(item.Name=="Name")
{
item.SetValue(DB1,"abc");
}
if(item.Name=="ID")
{
item.SetValue(DB1,100001);
}
}
var Property=Tp.GetProperty("属性名"[,BingDingFlags.NonPublic|BingDingFlags.Instance]) 【获取指定的属性名,加后面内容可以获取私有属性】
var Filed=Tp.GetFiled("字段名"[,BingDingFlags.NonPublic|BingDingFlags.Instance]) 【获取指定的字段名,加后面内容可以获取私有属性】

类:

使用Code First建模自引用关系笔记    asp.net core上使用redis探索(1)    asp.net mvc控制器激活全分析   语言入门必学的基础知识你还记得么?    反射
  public class Hello
    {
        public string Name{ get;  set; }
        string Sex { get;  set; } 

        public void PublicSayHello()
        {
            Console.WriteLine(string.Format(@"无参公有方法:{0} {1}! Hello! ", Sex, Name));
        }

        public void PublicSayHello(int tip)
        {
            Console.WriteLine(string.Format(@"带参公有方法 tip{2}:{0} {1}! Hello! ", Sex, Name,tip));
        }

        private void PrivateSayHello()
        {
            Console.WriteLine(string.Format(@"无参私有方法 :{0} {1}! Hello! ", Sex, Name));
        }

        public void PublicGenericSayHello<G>(G tip)
        {
            Console.WriteLine(string.Format(@"带参泛型公有方法 tip{2}:{0} {1}! Hello! ", Sex, Name, tip));
        }

        private Hello(string name,string sex="PrivateSex") { Name = name;Sex = sex; }

        public Hello() { Sex = "PublicSex"; }//因为定义了一个有参构造函数,所以需要

        public Hello(string name) { Name = name; Sex = "PublicSex"; }//因为定义了一个有参构造函数,所以需要
    }

    public class SayHello<T,W>
    {

        T LastName { get; set; }
        T FirstName { get; set; }
        W Age { get; set; }

        public void PublicSayHello()
        {
            Console.WriteLine(string.Format(@"无参公有方法:{0} {1},you are {2}!! ", FirstName, LastName, Age));
        }

        public SayHello(T firstName,T lastName, W age) { FirstName = firstName; LastName = lastName; Age = age; }
    }
使用Code First建模自引用关系笔记    asp.net core上使用redis探索(1)    asp.net mvc控制器激活全分析   语言入门必学的基础知识你还记得么?    反射

方法:注意将DLL的路径,完全限定的类型替换

使用Code First建模自引用关系笔记    asp.net core上使用redis探索(1)    asp.net mvc控制器激活全分析   语言入门必学的基础知识你还记得么?    反射
Assembly ass = Assembly.Load("ConsoleApp1");//获取bin下的dll
            Assembly Loadass = Assembly.LoadFrom(@"E:\laiji\WebApplication1\ConsoleApp1\bin\Debug\netcoreapp2.0\ConsoleApp1.dll");//获取路径下的dll
            Assembly Thisass = Assembly.GetExecutingAssembly();//获取本程序集的dll
            {
                Type T1 = ass.GetType("ConsoleApp1.Hello");
                Type T2 = Loadass.GetType("ConsoleApp1.Hello");
                Type T3 = Thisass.GetType("ConsoleApp1.Hello");
                Type T4 = typeof(Hello);//直接获取类型

                object[] Parms = new object[2];//参数列表,必须和构造函数的参数对应
                Parms[0] = "ObjectName";
                Parms[1] = "ObjectSex";

                var data1 = Activator.CreateInstance(T1) as Hello;//未进行转换无法调用下面的方法和赋值,调用无参公有构造函数
                data1.Name = "TestMan";
                data1.PublicSayHello();

                var data2 = Activator.CreateInstance(T1,new object[] { "PublicParmsName"}) as Hello;//未进行转换无法调用下面的方法和赋值,调用无参公有构造函数
                data2.PublicSayHello();

                //注意,使用的构造方法不同
                var PrivateData = ass.CreateInstance(T3.FullName, true, BindingFlags.Default | BindingFlags.Instance | BindingFlags.NonPublic, null, Parms, null, null) as Hello;//调用私有有参构造函数
                PrivateData.PublicSayHello();

                //调用方法
                {
                    Console.WriteLine("********************调用方法****************");
                    MethodInfo PublicMethod1 = T1.GetMethod("PublicSayHello", new Type[] { });//调用公有方法,如果方法没有重载可以省略new Type[] { }
                    PublicMethod1.Invoke(PrivateData, null);//null为参数列表,必须一一对应

                    MethodInfo PublicMethod2 = T1.GetMethod("PublicSayHello", new Type[] { typeof(int) });//调用公有方法,如果有重载,要在后面加上参数类型列表,必须一一对应
                    PublicMethod2.Invoke(PrivateData, new object[] { 1 });//null为参数列表,必须一一对应

                    MethodInfo PrivateMethod1 = T1.GetMethod("PrivateSayHello", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null);//调用私有方法
                    PrivateMethod1.Invoke(PrivateData, null);

                    MethodInfo PublicMethod3 = T1.GetMethod("PublicGenericSayHello");//调用泛型方法
                    MethodInfo Newmethod = PublicMethod3.MakeGenericMethod(typeof(int));
                    Newmethod.Invoke(PrivateData, new object[] { 1 });
                }

                //修改属性,字段
                {
                    Console.WriteLine("********************修改属性,字段****************");
                    //1.遍历获取,仅能获取公有属性
                    foreach (var item in T1.GetProperties())
                    {
                        item.SetValue(PrivateData, "SetValueForeach");//设置属性的值,为了方便,将所有属性的值都设为SetValueForeach
                    }
                    PrivateData.PublicSayHello();

                    //2.获取指定属性
                    PropertyInfo Pt1 = T1.GetProperty("Name");//公有属性
                    Pt1.SetValue(PrivateData, "SetValueUsePropertyName");
                    PrivateData.PublicSayHello();

                    PropertyInfo Pt2 = T1.GetProperty("Sex",BindingFlags.Instance|BindingFlags.NonPublic);//私有属性
                    Pt2.SetValue(PrivateData, "SetValueUsePropertyNameBySex");
                    PrivateData.PublicSayHello();

                    //字段同属性,仅将Property换成Field
                }
            }
            {
                Console.WriteLine("********************调用泛型构造函数****************");
                //泛型构造函数
                Type Tp = ass.GetType("ConsoleApp1.SayHello`2");//后面要带占位符`2
                Type NewType = Tp.MakeGenericType(typeof(string), typeof(int));//需要新建一个泛型类型
                var Data = Activator.CreateInstance(NewType, new object[] {"FFN","LLN",18 }) as SayHello<string,int>;//使用泛型类型创建实例
                Data.PublicSayHello();
            }
使用Code First建模自引用关系笔记    asp.net core上使用redis探索(1)    asp.net mvc控制器激活全分析   语言入门必学的基础知识你还记得么?    反射