net中的线程同步基础,使用WinApi操作剪切板Clipboard

by admin on 2019年5月3日

net中的线程同步基础,使用WinApi操作剪切板Clipboard。前言:

新近恰恰写三个先后,要求操作剪切板

作用相当的粗略,只要求从剪切板内读取字符串,然后清空剪切板,然后再把字符串导入剪切板

自个儿想当然的应用自家最善于的C#来完结那项专业,原因无他,因为.Net框架封装了能兑现那种功用的主意

下一场就有了之类代码

bf88必发唯一官网 1bf88必发唯一官网 2

 1             string Temp = "";
 2             while (true)
 3             {
 4                 string Tex = Clipboard.GetText().ToString();
 5                 if (!string.IsNullOrWhiteSpace(Tex) && Temp != Tex)
 6                 {
 7                     Clipboard.Clear();
 8                     Clipboard.SetDataObject(Tex, false);
 9                     Temp = Tex;
10                 }
11                 Thread.Sleep(1);
12             }

View Code

那段代码,也是网页上海大学规模流传的,使用.Net框架操作系统剪切板的形式,当然那个主目的在于少数情状下很得力

唯独在笔者那确发生了点问题,重要的主题素材有两点

先是,笔者对剪切板的操作要求有实时性,也正是,操作人士复制的须臾就活该截取到剪切板的多寡,管理完后再放入剪切板

结果

 Clipboard.SetDataObject(Tex, false);

没悟出上面那条设置剪切板的通令竟然会卡宗旨窗口的线程,比方说,笔者在A软件施行了一回复制操作,若是应用了上述代码,那么A软件强制线程堵塞大致几百微秒的指南,反正很影响体验,笔者想见是因为该命令会锁定内部存款和储蓄器导致的

那如何做,本着死马当活马医的神态,小编专门为该指令启用了二个线程

       Task.Factory.StartNew(()=> 
                    {
                        Clipboard.Clear();
                        Clipboard.SetDataObject(Text, false);
                    });

使用了线程以往,因为操作滞后(线程运转会延迟1会儿,并不实时)了,所以上述难点就像是缓慢解决了,不过没悟出出现了新的主题素材

 string Tex = Clipboard.GetText().ToString();

上述从剪切板得到字符串的指令,在默写情形下,会卡滞住,然后程序在一秒钟过后,因为超时而被系统注销

emmmmm,在经过几番努力未来,小编毕竟开采到,纵然.Net封装了过多操作系统API的格局,使得部分IO操作变轻松不少,不过带来的标题也是一致大的,在遇见不也许缓慢解决的主题素材的时候,会稍稍惊慌失措

于是乎无奈,笔者只可以放任采纳过C#姣好该项效率,想着幸好作用简单,而且操作WinAPI其实最佳的要么采取C++来写,于是笔者用C++复现了上述意义

bf88必发唯一官网 3bf88必发唯一官网 4

 1 #include "stdafx.h"
 2 #include <windows.h>
 3 #include <iostream>
 4 using namespace std;
 5 #pragma comment(linker,"/subsystem:windows /entry:mainCRTStartup")
 6 
 7 int main(int argc, _TCHAR* argv[])
 8 {
 9     HANDLE THandle = GlobalAlloc(GMEM_FIXED, 1000);//分配内存
10     char* Temp = (char*)THandle;//锁定内存,返回申请内存的首地址
11     while (true)
12     {
13         HWND hWnd = NULL;
14         OpenClipboard(hWnd);//打开剪切板
15         if (IsClipboardFormatAvailable(CF_TEXT))
16         {
17             HANDLE h = GetClipboardData(CF_TEXT);//获取剪切板数据
18             char* p = (char*)GlobalLock(h);
19             GlobalUnlock(h);
20             if (strcmp(Temp, p))
21             {
22                 EmptyClipboard();//清空剪切板
23                 HANDLE hHandle = GlobalAlloc(GMEM_FIXED, 1000);//分配内存
24                 char* pData = (char*)GlobalLock(hHandle);//锁定内存,返回申请内存的首地址
25                 strcpy(pData, p);
26                 strcpy(Temp, p);
27                 SetClipboardData(CF_TEXT, hHandle);//设置剪切板数据
28                 GlobalUnlock(hHandle);//解除锁定
29             }
30         }
31         CloseClipboard();//关闭剪切板
32         Sleep(500);
33     }
34     return 0;
35 }

View Code

名符其实是C++,使用上述代码后,完美兑现本人急需的效劳,而且无论是主程序,依然本人写的这一个顺序,都不会现出卡滞或然不办事的情景了,真是可喜可贺。

那正是说本课程就到此截至。

 

 

 

 

线程安全

style=”font-size: 一5px”>此类型的持有国有静态(Visual Basic 中为 Shared)成员对八线程操作来说都以安枕无忧的。但不保证别的实例成员是线程安全的。

在MSDN上时时会看到如此一句话。表示只要程序中有n个线程调用那一个点子,那么那n个线程都是平安的,
可是实例成员就不可能担保了。

譬如Math.马克斯方法,不管有稍许个线程调用,都不会并发线程不安全的情事。

列举一个由于二十四线程引起的数据不安全。

bf88必发唯一官网 5bf88必发唯一官网 6

static void Main(string[] args)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    int sum = 0;
    var t1 = Task.Run(() =>
    {
        for (int i = 0; i < 3000000; i++)
        {
            sum += i;
        }
    });
    var t2 = Task.Run(() =>
    {
        for (int i = 3000000; i < 5000000; i++)
        {
            sum += i;
        }
    });

    Task.WaitAll(t1, t2);
    Console.WriteLine("和:"+ sum);
    Console.WriteLine("用时:"+watch.ElapsedMilliseconds);
}

View Code

和:-1271379077

用时:48

请按放肆键继续. . .

恐怕恐怕有人不知底,为啥产生那些负的了,作者以线程一,线程二分别表示t一,t二运营时候的线程。

 线程1  线程2  sum
 刚进入循环i=0    0
   刚进入循环i=0  0
   sum=sum+i=0+0=0;    i=i+1=1;  0
 sum=sum+i=0+0=0;    i=i+1=1;    0
   sum=sum+i=0+1=1;    i=i+1=2;  1
   sum=sum+i=1+2=3;    i=i+1=3  3
 sum=sum+i=3+1=4;    i=i+1=2;       1

 通过表格最终壹行,我们开采,今年线程一,希望的sum=0,可是被线程贰改换了。

 线程不安全的真相:二个线程想要的数目被此外线程改变了

 怎么消除?小编想许四个人想必都会(当然,小编也是)lock,lock,lock

bf88必发唯一官网 7bf88必发唯一官网 8

private static readonly object objAsync = new object();
static void Main(string[] args)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    int sum = 0;
    var t1 = Task.Run(() =>
    {
        for (int i = 0; i < 3000000; i++)
        {
            lock (objAsync)
            {
                sum += i;
            }
        }
    });
    var t2 = Task.Run(() =>
    {
        for (int i = 3000000; i < 5000000; i++)
        {
            lock (objAsync)
            {
                sum += i;
            }
        }
    });

    Task.WaitAll(t1, t2);
    Console.WriteLine("和:" + sum);
    Console.WriteLine("用时:" + watch.ElapsedMilliseconds);
}

View Code

和:1642668640

用时:461

请按任性键继续. . .

思考

实质上这里的例证完全能够不通过加锁来消除,可是为了展现加锁带来的负面影响,就很精晓了,线程同步是急需代价的;

以下是本文

想着,既然自身能用C++调用WinAPI完美兑现小编急需的功力,而且C#也能调用非托管的代码来实行WinAPI,那么作者不是足以把上边C++写的代码移植到C#个中实行?说干就干

首先,C#调用WinAPI必要先表明

        [DllImport("User32")]
        internal static extern bool OpenClipboard(IntPtr hWndNewOwner);

        [DllImport("User32")]
        internal static extern bool CloseClipboard();

        [DllImport("User32")]
        internal static extern bool EmptyClipboard();

        [DllImport("User32")]
        internal static extern bool IsClipboardFormatAvailable(int format);

        [DllImport("User32")]
        internal static extern IntPtr GetClipboardData(int uFormat);

        [DllImport("User32", CharSet = CharSet.Unicode)]
        internal static extern IntPtr SetClipboardData(int uFormat, IntPtr hMem);

操作剪切板要求调用的API差不离就地方这几个

有了API未来,我们还索要团结手动封装方法

     internal static void SetText(string text)
        {
            if (!OpenClipboard(IntPtr.Zero))
        {
        SetText(text);
        return;
        }
            EmptyClipboard();
            SetClipboardData(13, Marshal.StringToHGlobalUni(text));
            CloseClipboard();
        }

        internal static string GetText(int format)
        {
            string value = string.Empty;
            OpenClipboard(IntPtr.Zero);
            if (IsClipboardFormatAvailable(format))
            {
                IntPtr ptr = NativeMethods.GetClipboardData(format);
                if (ptr != IntPtr.Zero)
                {
                    value = Marshal.PtrToStringUni(ptr);
                }
            }
            CloseClipboard();
            return value;
        }

我们也就用到三个措施,从剪切板得到文本和安装文本到剪切板,哦关于SetClipboardData的率先个参数一3是怎么来的难点,其实那几个剪切板的格式参数,上面有一张表,正是自从这里来的

bf88必发唯一官网 9bf88必发唯一官网 10

public static class ClipboardFormat
{
    /// <summary>
    /// Text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals
    /// the end of the data. Use this format for ANSI text.
    /// </summary>
    public const int CF_TEXT = 1;

    /// <summary>
    /// A handle to a bitmap (<c>HBITMAP</c>).
    /// </summary>
    public const int CF_BITMAP = 2;

    /// <summary>
    /// Handle to a metafile picture format as defined by the <c>METAFILEPICT</c> structure. When passing a
    /// <c>CF_METAFILEPICT</c> handle by means of DDE, the application responsible for deleting <c>hMem</c> should
    /// also free the metafile referred to by the <c>CF_METAFILEPICT</c> handle.
    /// </summary>
    public const int CF_METAFILEPICT = 3;

    /// <summary>
    /// Microsoft Symbolic Link (SYLK) format.
    /// </summary>
    public const int CF_SYLK = 4;

    /// <summary>
    /// Software Arts' Data Interchange Format.
    /// </summary>
    public const int CF_DIF = 5;

    /// <summary>
    /// Tagged-image file format.
    /// </summary>
    public const int CF_TIFF = 6;

    /// <summary>
    /// Text format containing characters in the OEM character set. Each line ends with a carriage return/linefeed
    /// (CR-LF) combination. A null character signals the end of the data.
    /// </summary>
    public const int CF_OEMTEXT = 7;

    /// <summary>
    /// A memory object containing a <c>BITMAPINFO</c> structure followed by the bitmap bits.
    /// </summary>
    public const int CF_DIB = 8;

    /// <summary>
    /// Handle to a color palette. Whenever an application places data in the clipboard that depends on or assumes
    /// a color palette, it should place the palette on the clipboard as well. If the clipboard contains data in
    /// the <see cref="CF_PALETTE"/> (logical color palette) format, the application should use the
    /// <c>SelectPalette</c> and <c>RealizePalette</c> functions to realize (compare) any other data in the
    /// clipboard against that logical palette. When displaying clipboard data, the clipboard always uses as its
    /// current palette any object on the clipboard that is in the <c>CF_PALETTE</c> format.
    /// </summary>
    public const int CF_PALETTE = 9;

    /// <summary>
    /// Data for the pen extensions to the Microsoft Windows for Pen Computing.
    /// </summary>
    public const int CF_PENDATA = 10;

    /// <summary>
    /// Represents audio data more complex than can be represented in a CF_WAVE standard wave format.
    /// </summary>
    public const int CF_RIFF = 11;

    /// <summary>
    /// Represents audio data in one of the standard wave formats, such as 11 kHz or 22 kHz PCM.
    /// </summary>
    public const int CF_WAVE = 12;

    /// <summary>
    /// Unicode text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character
    /// signals the end of the data.
    /// </summary>
    public const int CF_UNICODETEXT = 13;

    /// <summary>
    /// A handle to an enhanced metafile (<c>HENHMETAFILE</c>).
    /// </summary>
    public const int CF_ENHMETAFILE = 14;

    /// <summary>
    /// A handle to type <c>HDROP</c> that identifies a list of files. An application can retrieve information
    /// about the files by passing the handle to the <c>DragQueryFile</c> function.
    /// </summary>
    public const int CF_HDROP = 15;

    /// <summary>
    /// The data is a handle to the locale identifier associated with text in the clipboard. When you close the
    /// clipboard, if it contains <c>CF_TEXT</c> data but no <c>CF_LOCALE</c> data, the system automatically sets
    /// the <c>CF_LOCALE</c> format to the current input language. You can use the <c>CF_LOCALE</c> format to
    /// associate a different locale with the clipboard text.
    /// An application that pastes text from the clipboard can retrieve this format to determine which character
    /// set was used to generate the text.
    /// Note that the clipboard does not support plain text in multiple character sets. To achieve this, use a
    /// formatted text data type such as RTF instead. 
    /// The system uses the code page associated with <c>CF_LOCALE</c> to implicitly convert from
    /// <see cref="CF_TEXT"/> to <see cref="CF_UNICODETEXT"/>. Therefore, the correct code page table is used for
    /// the conversion.
    /// </summary>
    public const int CF_LOCALE = 16;

    /// <summary>
    /// A memory object containing a <c>BITMAPV5HEADER</c> structure followed by the bitmap color space
    /// information and the bitmap bits.
    /// </summary>
    public const int CF_DIBV5 = 17;

    /// <summary>
    /// Owner-display format. The clipboard owner must display and update the clipboard viewer window, and receive
    /// the <see cref="ClipboardMessages.WM_ASKCBFORMATNAME"/>, <see cref="ClipboardMessages.WM_HSCROLLCLIPBOARD"/>,
    /// <see cref="ClipboardMessages.WM_PAINTCLIPBOARD"/>, <see cref="ClipboardMessages.WM_SIZECLIPBOARD"/>, and
    /// <see cref="ClipboardMessages.WM_VSCROLLCLIPBOARD"/> messages. The <c>hMem</c> parameter must be <c>null</c>.
    /// </summary>
    public const int CF_OWNERDISPLAY = 0x0080;

    /// <summary>
    /// Text display format associated with a private format. The <c>hMem</c> parameter must be a handle to data
    /// that can be displayed in text format in lieu of the privately formatted data.
    /// </summary>
    public const int CF_DSPTEXT = 0x0081;

    /// <summary>
    /// Bitmap display format associated with a private format. The <c>hMem</c> parameter must be a handle to
    /// data that can be displayed in bitmap format in lieu of the privately formatted data.
    /// </summary>
    public const int CF_DSPBITMAP = 0x0082;

    /// <summary>
    /// Metafile-picture display format associated with a private format. The <c>hMem</c> parameter must be a
    /// handle to data that can be displayed in metafile-picture format in lieu of the privately formatted data.
    /// </summary>
    public const int CF_DSPMETAFILEPICT = 0x0083;

    /// <summary>
    /// Enhanced metafile display format associated with a private format. The <c>hMem</c> parameter must be a
    /// handle to data that can be displayed in enhanced metafile format in lieu of the privately formatted data.
    /// </summary>
    public const int CF_DSPENHMETAFILE = 0x008E;

    /// <summary>
    /// Start of a range of integer values for application-defined GDI object clipboard formats. The end of the
    /// range is <see cref="CF_GDIOBJLAST"/>. Handles associated with clipboard formats in this range are not
    /// automatically deleted using the <c>GlobalFree</c> function when the clipboard is emptied. Also, when using
    /// values in this range, the <c>hMem</c> parameter is not a handle to a GDI object, but is a handle allocated
    /// by the <c>GlobalAlloc</c> function with the <c>GMEM_MOVEABLE</c> flag.
    /// </summary>
    public const int CF_GDIOBJFIRST = 0x0300;

    /// <summary>
    /// See <see cref="CF_GDIOBJFIRST"/>.
    /// </summary>
    public const int CF_GDIOBJLAST = 0x03FF;

    /// <summary>
    /// Start of a range of integer values for private clipboard formats. The range ends with
    /// <see cref="CF_PRIVATELAST"/>. Handles associated with private clipboard formats are not freed
    /// automatically; the clipboard owner must free such handles, typically in response to the
    /// <see cref="ClipboardMessages.WM_DESTROYCLIPBOARD"/> message.
    /// </summary>
    public const int CF_PRIVATEFIRST = 0x0200;

    /// <summary>
    /// See <see cref="CF_PRIVATEFIRST"/>.
    /// </summary>
    public const int CF_PRIVATELAST = 0x02FF;
}

View Code

在C++里面是毫无钦点数字的,只供给用CF_UNICODETEXT就行,不过.Net里面应该未有对号入座的索引表,所以只可以手动输入(小编这里是为着声明用才专门用数字,本身代码那是索引的枚举类)

下边八个干活做完事后,就能够促功效益了,功用代码如下

                   var LastS = string.Empty;
                   while (!CancelInfoClipboard.IsCancellationRequested)
                   {
                       var Temp = ClipboardControl.GetText(ClipboardFormat.CF_UNICODETEXT);
                       if (!string.IsNullOrEmpty(Temp) && Temp != LastS)
                       {
                           ClipboardControl.SetText(Temp);
                           LastS = Temp;
                       }
                       Thread.Sleep(50);
                   }

net中的线程同步基础,使用WinApi操作剪切板Clipboard。是或不是和最开首呈现的调用.Net框架的办法1致(笑),然则使用底层API完结的职能,就从不那么多乱7捌糟的Bug了,本人也很领会到底达成了啥功能,同时也赢得了诸多新知识(重假设非托管代码调用的时候的注意事项什么的,还有,向非托管代码传递数据的时候,最广大用马尔斯hal类里面包车型客车艺术,不然或者会出错,究竟那几个类正是专程为非托管代码而举行的)

 

 

原子操作

为啥要给sum += i加锁,因为它是不原子操作,五个线程同时操作就能够发生竞态条件

style=”font-size: 1四px”>百度百科:原子操作是无需一齐的,那是.Netbf88必发唯一官网 1110②线程编制程序的老生常谈了。所谓原子操作是指不会被线程调整机制打断的操作;那种操作1旦开端,就直接运行到甘休,中间不会有别的context switch (换来另贰个线程)

在.net中,CL宝马7系有限帮衬一下品种的读写是原子性的。Boolean、Char、(S)Byte、(U)Int1六、(U)Int3二、(U)IntPtr、Single、引用类型。不包涵Double、Int6四、(U)Int64.

原理:CL奥迪Q5保险四字节以内的根底项目标读写是原子性的。因为对此Int6四类型变量的读写,只要施行一遍相应的机器指令。

接下去是新的觉察

在商量MSDN上边境海关于剪切板的API的时候,开掘了一个函数

bool AddClipboardFormatListener(HWND hwnd);

依据描述来说,是增加一个剪切板的监察和控制,在剪切板有其余更改的时候,文告你所钦点的句柄的窗口,笔者一想,那不就是作者所急需的么,有了那样三个API未来,其实自身下边所突显的,使用死循环轮询剪切板的不贰秘技就变得很傻逼,而且也很轻巧失误了,于是,基于那个新意识的API,作者再也退换了全方位的程序逻辑,反而比原来的兑现更为简明了。

率先大家须求3个新的窗口或然控件来收取Windows音讯更新后所发来的音信,只要New
一个form就行

        public Form2()
        {
            InitializeComponent();
            AddClipboardFormatListener(this.Handle);
        }

然后我们在初步化组件的命令后边,把利用增多剪切板监听的API把当前窗口的句柄发给系统,那样系统在收受到剪切板改造的授命后,会把消息发给当前窗口

然后我们须要复写WndProc方法

   protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x031D && Onice)
            {var Temp = ClipboardControl.GetText(ClipboardFormat.CF_UNICODETEXT);
                    if (!string.IsNullOrEmpty(Temp))
                    {
                        ClipboardControl.SetText(Temp);
                        Onice = false;
                    }
            }
            else if (!Onice)
            {
                Onice = true;
            }
            else
            {
                base.WndProc(ref m);
            }
        }
   private bool Onice = true;

首先WndProc假使是Form类下边八个专门用来接受系统一发布送过来的新闻的法子

接下来关于m.Msg == 0x03壹D的0x03一D在WinAPI定义上的含义是WM_CLIPBOA瑞鹰DUPDATE
,相当于剪切板更新事件,那个通过寻找MSDN能够找到

上边未有专门意外的函数,正是有某个须要注意,我们这里设置了剪切板数据,相当于进行了一回立异,所以会在这一弹指间重新发生剪切板更新事件,然后又会通告那一个主意,然后就能产生死循环,作者在此地用了2个布尔剖断来由此布尔状态调节是或不是截取剪切板,不唯有有未有更加好的格局来达成

以上

 

 

线程同步

对于线程同步,有用户格局和基本情势三种,由于用户形式速度明显快于内核格局。

用户格局:提供新鲜的CPU指令来协和线程,意味着和睦是在硬件中爆发的,缺点是操作系统和CL凯雷德长久检查测试不到三个线程在用户方式上过不去了,线程池也不会创建新的线程来替换一时阻塞的线程,这一个CPU指令阻塞非常的短的小运。

水源形式:由操作系统提供,优点通过基础格局获得别的线程具有的资源时,Windows会阻塞线程避防止它浪费CPU时间,能源可用时,苏醒线程,允许它访问财富。

 

 

Volatile

bf88必发唯一官网 12bf88必发唯一官网 13

private int flag = 0;
private int number = 0;
public void Thread1()
{
    number = 5;
    flag = 1;
}
public void Thread2()
{
    if (flag == 1)
    {
        Console.WriteLine(number);
    }
}

View Code

Thread第11中学先将value赋值为0,再把flag赋值为一,按道理说在Thread第22中学,就算flag为一了,那么value必定为5,实际上不是那样子的,C#编写翻译器,JIT编写翻译器,CPU会优化代码,导致Thread第11中学实行顺序不明了,作者也是服了,那有哪些用,为啥要做这么的优化!!!

可以透过Volatile.Read或Volatile.Write阻止那种优化。Volatile.Read有限支撑提供的变量中的值在调用时读取,并且在此以前的加载和仓库储存操作是鲁人持竿大家的编码顺序,Volatile.Write保险提供的变量中的值在调用时写入,并且之后的加载和仓库储存操作是依据大家的编码顺序。volatile不能够用来线程同步。这里有点坑啊认为

bf88必发唯一官网 14bf88必发唯一官网 15

private int flag = 0;
private int number = 0;
public void Thread1()
{
    number = 5;
    Volatile.Write(ref flag, 1);
}
public void Thread2()
{
    if (Volatile.Read(ref flag) == 1)
    {
        Console.WriteLine(number);
    }
}

View Code

 也足以透过volatile关键字来定义变量,效果是同样的。

bf88必发唯一官网 16bf88必发唯一官网 17

private volatile int flag = 0;
private int number = 0;
public void Thread1()
{
    number = 5;
    flag = 1;
}
public void Thread2()
{
    if (flag == 1)
    {
        Console.WriteLine(number);
    }
}

View Code

Asp.Net.Identity为啥物请自行检索,也可转化此文章

Asp.Net.Identity为什么物请自行检索,也可转化此文章

Interlocked

 Interlocked提供了1组用来原子操作的静态方法。

 int Add(ref int location1, int value)  原子加法操作,支持long
 int Decrement(ref int location)  原子自减
 int Decrement(ref int location)  原子自增
 int Exchange(ref int location1, int value)  原子交换
 int CompareExchange(ref int location1, int value, int comparand)  原子比较交换

这么些措施基本都同时援助int、long、double、float、object的。解释一下最后一个方法。

CompareExchange:要是location壹等于comparand,就把value赋值给它。语法和底下的代码同样。

int location1 = 1;
int comparand = 1;
int value = 2;
if(location1 == comparand)
{
    location1 = value;
}

如若上边的连串不能满意呢?

使用Interlocked实现自旋锁让三个线程在原地打转,防止它跑去和另1个线程竞争财富,可是会浪费宝贵的CPU时间,自旋锁应该用于维护那多少个会进行的可怜快的代码区域。

bf88必发唯一官网 18bf88必发唯一官网 19

struct SimpleSpinLock
{
    private int m_ResourceInUse;
    public void Enter()
    {
        while (true)
        {
            if (Interlocked.Exchange(ref m_ResourceInUse, 1) == 0
            {
                return;
            }
        }
    }
    public void Leave()
    {
        Volatile.Write(ref m_ResourceInUse, 0);
    }
}
 static int sum = 0;
static void Main(string[] args)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    SimpleSpinLock  g= new SimpleSpinLock();
    var t1 = Task.Run(() =>
    {
        for (int i = 0; i < 3000000; i++)
        {
            g.Enter();
            sum += i;
            g.Leave();
        }
    });
    var t2 = Task.Run(() =>
    {
        for (int i = 3000000; i < 5000000; i++)
        {
            g.Enter();
            sum += i;
            g.Leave();
        }
    });
    Task.WaitAll(t1, t2);
    Console.WriteLine("和:" + sum);
    Console.WriteLine("用时:" + watch.ElapsedMilliseconds);
}

View Code

和:1642668640

用时:610

请按大肆键继续. . .

本来微软早已帮我们将授权、认证以及数据库存款和储蓄都1一管理好了。不过总有那种场馆,如作者辈后天的等级次序是现已存在了数据库,且Curry已经有用户、角色等音讯表,不过

理所当然微软已经帮大家将授权、认证以及数据仓库储存款和储蓄都相继管理好了。不过总有那种场所,如小编辈以往的等级次序是早已存在了数据库,且Curry已经有用户、剧中人物等新闻表,可是

WaitHandle

 抽象类,封装四个Windows内核查象句柄。

bf88必发唯一官网 20bf88必发唯一官网 21

  //封装等待对共享资源的独占访问的操作系统特定的对象。
  public abstract class WaitHandle : MarshalByRefObject, IDisposable
   {
        public const int WaitTimeout = 258;

        protected static readonly IntPtr InvalidHandle;

        protected WaitHandle();

        [Obsolete("Use the SafeWaitHandle property instead.")]
        public virtual IntPtr Handle { get; set; }
    //获取或设置本机操作系统句柄。

        public SafeWaitHandle SafeWaitHandle { get; set; }

    //向一个 System.Threading.WaitHandle 发出信号并等待另一个,指定超时间隔为 32 位有符号整数,并指定在进入等待前是否退出上下文的同步域。
        public static bool SignalAndWait(WaitHandle toSignal, WaitHandle toWaitOn);

    //等待指定数组中的所有元素收到信号,使用 System.Int32 值指定时间间隔,并指定是否在等待之前退出同步域。都收到信号返回true
        public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout);

    //等待指定数组中的任一元素收到信号,使用 32 位带符号整数指定时间间隔并指定是否在等待之前退出同步域。返回收到信号的对象的数组索引
        public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext);

        public virtual void Close();

    //阻止当前线程,直到当前的 System.Threading.WaitHandle 收到信号为止,同时使用 32 位带符号整数指定时间间隔,并指定是否在等待之前退出同步域。收到信号返回true
        public virtual bool WaitOne(TimeSpan timeout, bool exitContext);

        protected virtual void Dispose(bool explicitDisposing);
    }

View Code

我们仍旧贪婪想行使微软的授权、认证类库。这里作者就来实在实行下到底可行不可行~

笔者们依然贪婪想选取微软的授权、认证类库。这里自个儿就来其实实践下到底可行不可行~

EventWaitHandle

bf88必发唯一官网 22bf88必发唯一官网 23

//表示一个线程同步事件。
public class EventWaitHandle : WaitHandle
{
    //     初始化 System.Threading.EventWaitHandle 类的新实例,并指定在此调用后创建的等待句柄最初是否处于终止状态,它是自动重置还是手动重置,系统同步事件的名称,一个
    //     Boolean 变量(其值在调用后表示是否创建了已命名的系统事件),以及应用于已命名的事件(如果创建了该事件)的访问控制安全性。
    public EventWaitHandle(bool initialState, EventResetMode mode, string name, out bool createdNew, EventWaitHandleSecurity eventSecurity);

    //     打开指定名称为同步事件(如果已经存在)。
    public static EventWaitHandle OpenExisting(string name);

    //     用安全访问权限打开指定名称为同步事件(如果已经存在)。
    public static EventWaitHandle OpenExisting(string name, EventWaitHandleRights rights);

    //     打开指定名称为同步事件(如果已经存在),并返回指示操作是否成功的值。
    public static bool TryOpenExisting(string name, out EventWaitHandle result);

    //     用安全访问权限打开指定名称为同步事件(如果已经存在),并返回指示操作是否成功的值。
    public static bool TryOpenExisting(string name, EventWaitHandleRights rights, out EventWaitHandle result);

    //     获取 System.Security.AccessControl.EventWaitHandleSecurity 对象,该对象表示由当前 System.Threading.EventWaitHandle
    //     对象表示的已命名系统事件的访问控制安全性。
    public EventWaitHandleSecurity GetAccessControl();

    //     将事件状态设置为非终止状态,导致线程阻止。
    public bool Reset();

    //     将事件状态设置为终止状态,允许一个或多个等待线程继续。
    public bool Set();

    //     设置已命名的系统事件的访问控制安全性。
    public void SetAccessControl(EventWaitHandleSecurity eventSecurity);
}

View Code

先是步、新建多个Asp.Net MVC框架的web工程

第二步、新建3个Asp.Net MVC框架的web工程

AutoResetEvent

bf88必发唯一官网 24bf88必发唯一官网 25

//
// 摘要:
//     通知正在等待的线程已发生事件。此类不能被继承。
public sealed class AutoResetEvent : EventWaitHandle
{
    //
    // 摘要:
    //     使用 Boolean 值(指示是否将初始状态设置为终止的)初始化 System.Threading.AutoResetEvent 类的新实例。
    //
    // 参数:
    //   initialState:
    //     若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false。
    public AutoResetEvent(bool initialState);
}

View Code

 使用伊芙ntWaitHandle子类AutoResetEvent创建线程同步锁,效果和Interlocked的自旋锁同样的,可是作用要慢诸多,可是此地未有抢占成功的线程会阻塞,不会自旋。

bf88必发唯一官网 26bf88必发唯一官网 27

class SimpleWaitLock
{
    private AutoResetEvent m_ResourceInUse;
    public SimpleWaitLock()
    {
        m_ResourceInUse = new AutoResetEvent(true);
     }
    public void Enter()
    {
        m_ResourceInUse.WaitOne();
    }
    public void Leave()
    {
        m_ResourceInUse.Set();
    }
}

View Code

第二部、Nuget上安装Microsoft.AspNet.Identity、Microsoft.AspNet.Identity.Owin

第二部、Nuget上安装Microsoft.AspNet.Identity、Microsoft.AspNet.Identity.Owin

Semaphore

bf88必发唯一官网 28bf88必发唯一官网 29

//限制可同时访问某一资源或资源池的线程数。
public sealed class Semaphore : WaitHandle
{
    //     初始化 System.Threading.Semaphore 类的新实例,并指定初始入口数和最大并发入口数,可以选择指定系统信号量对象的名称,
    //     指定一个变量来接收指示是否创建了新系统信号量的值,以及指定系统信号量的安全访问控制。
    public Semaphore(int initialCount, int maximumCount, string name, out bool createdNew, SemaphoreSecurity semaphoreSecurity);

    //     用安全访问权限打开指定名称为信号量(如果已经存在)。
    public static Semaphore OpenExisting(string name, SemaphoreRights rights);

    //     用安全访问权限打开指定名称为信号量(如果已经存在),并返回指示操作是否成功的值。
    public static bool TryOpenExisting(string name, SemaphoreRights rights, out Semaphore result);

    //     获取已命名的系统信号量的访问控制安全性。
    public SemaphoreSecurity GetAccessControl();
    //     退出信号量并返回前一个计数。

    public int Release();
    //     以指定的次数退出信号量并返回前一个计数。
    public int Release(int releaseCount);

    //     设置已命名的系统信号量的访问控制安全性。
    public void SetAccessControl(SemaphoreSecurity semaphoreSecurity);
}

View Code

里面Microsoft.AspNet.Identity.Owin有依赖项,它依附了那多少个包:

当中Microsoft.AspNet.Identity.Owin有依据项,它依附了这多少个包:

Mutex

 Mutex代表互斥体,和AutoReset伊夫nt和计数为一的Semaphore相似,叁者都以二次只释放一个正值班守护候的线程。

bf88必发唯一官网 30bf88必发唯一官网 31

//
// 摘要:
//     还可用于进程间同步的同步基元。
public sealed class Mutex : WaitHandle
{
    //     使用可指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称的 Boolean 
    //     值和当线程返回时可指示调用线程是否已赋予互斥体的初始所有权以及访问控制安全是否已应用到命名互斥体的
    //     Boolean 变量初始化 System.Threading.Mutex 类的新实例。
    public Mutex(bool initiallyOwned, string name, out bool createdNew, MutexSecurity mutexSecurity);

    //     利用所需的安全访问权限,打开指定的已命名的互斥体(如果已经存在)。
    public static Mutex OpenExisting(string name, MutexRights rights);

    //     利用所需的安全访问权限,打开指定的已命名的互斥体(如果已经存在),并返回指示操作是否成功的值。
    public static bool TryOpenExisting(string name, MutexRights rights, out Mutex result);

    //     获取表示已命名的互斥体的访问控制安全性的 System.Security.AccessControl.MutexSecurity 对象。
    public MutexSecurity GetAccessControl();

    //     释放 System.Threading.Mutex 一次。
    public void ReleaseMutex();

    //     设置已命名的系统互斥体的访问控制安全性。
    public void SetAccessControl(MutexSecurity mutexSecurity);
}

View Code

 Mutex帮忙递归,当调用M一时获得Mutext试行了线程安全的操作,调用M二时,照旧可以施行线程安全的操作,此时只假使AutoReset伊芙nt对象就可以在M二方法中梗阻。

bf88必发唯一官网 32bf88必发唯一官网 33

class SomeClass : IDisposable
{
    private readonly Mutex m_lock = new Mutex();

    public void Dispose()
    {
        m_lock.Dispose();
    }

    public void M1()
    {
        m_lock.WaitOne();
        //do somethine safe
        M2();
        m_lock.ReleaseMutex();
    }
    public void M2()
    {
        m_lock.WaitOne();
        //do something safe
        m_lock.ReleaseMutex();
    }
}

View Code

 AutoReset伊夫nt也能够兑现递归锁,效能比Mutex高

bf88必发唯一官网 34bf88必发唯一官网 35

class RecurisveAutoResetEvent : IDisposable
{
    private AutoResetEvent m_lock = new AutoResetEvent(true);
    private int m_owningThread = 0;
    private int m_recursionCount = 0;

    public void Dispose()
    {
        m_lock.Dispose();
    }

    public void Enter()
    {
        int currentThreadId = Thread.CurrentThread.ManagedThreadId;
        //如果调用线程拥有锁,就再递归一次
        if(m_owningThread == currentThreadId)
        {
            m_recursionCount++;
            return;
        }
        //没有锁,就等待它
        m_lock.WaitOne();

        //调用线程拥有了锁,初始化线程id和计数
        m_owningThread = currentThreadId;
        m_recursionCount = 1;
    }
    public void Leave()
    {
        //如果调用线程没有锁,就出错了
        if(m_owningThread != Thread.CurrentThread.ManagedThreadId)
        {
            throw new InvalidOperationException();
        }
        //递归数减一
        if(--m_recursionCount == 0)
        {
            //如果为0,表名该线程没有锁了
            m_owningThread = 0;
            //唤醒等待的另一个线程
            m_lock.Set();
        }
    }
}

View Code

Microsoft.Owin.Security.OAuth      MSDN申明:包蕴与 OAuth
提供程序相关的花色。(详细音信参考
)

Microsoft.Owin.Security.OAuth      MSDN注脚:包罗与 OAuth
提供程序相关的品类。(详细音讯参考
)

线程同步之混合情势

 未有线程竞争时,混合形式提供了用户格局抱有具备的个性优势,有竞争时,混合方式应用了基石方式提供不自旋的优势(幸免浪费CPU时间)

Microsoft.Owin.Security.Cookies   MSDN注明:提供与身份 cookie
相关的项目。     (详细新闻参考
)

Microsoft.Owin.Security.Cookies   MSDN表明:提供与身份 cookie
相关的连串。     (详细音讯参考
)

应用Interlocked和AutoReset伊夫nt自定义混合锁

bf88必发唯一官网 36bf88必发唯一官网 37

class SimpleHybridLock : IDisposable
{
    private int m_waiters = 0;
    private AutoResetEvent m_waiterLock = new AutoResetEvent(false);

    public void Dispose()
    {
        m_waiterLock.Dispose();
    }

    public void Enter()
    {
        //这个线程想要获得锁
        if(Interlocked.Increment(ref m_waiters) == 1)
        {//无竞争,获得成功
            return;
        }
        //获得失败,没有自旋
        //而是使线程等待
        m_waiterLock.WaitOne();
        //到这里线程拿到了锁
    }
    public void Leave()
    {
        //这个线程想要释放锁
        if (Interlocked.Decrement(ref m_waiters) == 0)
        {
            //没有其他线程等待,直接返回
            return;
        }
        //有其他线程正在阻塞,唤醒其中一个
        m_waiterLock.Set();
    }
}

View Code

 同样用以前的顺序开始展览测试。显然要比唯有的水源形式要快大多,但是出于调换内核情势形成品质的损失,结果只怕比仅仅的用户方式慢繁多。

和:1642668640

用时:11855

请按任意键继续. . .

Microsoft.Owin.Security                
MSDN申明:包括与身份验证相关的品种。         (详细新闻参考
)

Microsoft.Owin.Security                
MSDN注脚:蕴涵与身份验证相关的品类。         (详细音信参考
)

自旋片刻的混合锁

 通过上边的事例我们明白,转变内核方式会变成巨大的性质损失。而平时线程占领锁的小运都万分短,所以可以让线程自旋一小段时日,再转为内核方式。这样能够幸免,一境遇静态条件就转为内核形式幸免的品质消耗,由于占用时间比相当的短,自旋的进度中就只怕获得锁了。

bf88必发唯一官网 38bf88必发唯一官网 39

class AnotherHybridLock : IDisposable
{
    //用户模式
    private int m_waiters = 0;
    //内核模式
    private AutoResetEvent m_waiterLock = new AutoResetEvent(false);
    //控制自旋
    private int m_spincount = 4000;
    //当前线程,当前线程占用数
    private int m_owingThreadId = 0, m_recursion = 0;

    public void Dispose()
    {
        m_waiterLock.Dispose();
    }

    public void Enter()
    {
        int currentThreadId = Thread.CurrentThread.ManagedThreadId;
        //如果调用线程拥有锁,就再递归一次
        if (m_owingThreadId == currentThreadId)
        {
            m_recursion++;
            return;
        }
        //尝试获取
        SpinWait spinwait = new SpinWait();
        for(int i = 0; i < m_spincount; i++)
        {
            //如果锁可以使用了,这个线程就获得它,设置状态并返回
            if (Interlocked.CompareExchange(ref m_waiters, 1, 0) == 0)
                goto GotLock;
            //给其他线程运行的机会,希望锁会被释放
            spinwait.SpinOnce();
        }
        //自旋结束,仍未获得锁,再试一次
        if(Interlocked.Increment(ref m_waiters) > 1)
        {
            //仍是竞态条件,阻塞
            m_waiterLock.WaitOne();
            //新来时拥有锁了。。。
        }
        GotLock:
        //获得锁了。。
        m_owingThreadId = currentThreadId;
        m_recursion = 1;
    }
    public void Leave()
    {
        int currentThreadId = Thread.CurrentThread.ManagedThreadId;

        if (m_owingThreadId != currentThreadId)
        {
            throw new InvalidOperationException();
        }
        //如果这个线程仍然有锁,直接返回
        if(--m_recursion > 0)
        {
            return;
        }
        //现在没有线程拥有锁
        m_owingThreadId = 0;

        //如果没有其他线程等待,直接返回
        if(Interlocked.Decrement(ref m_waiters) == 0)
        {
            return;
        }
        //有线程等待,唤醒一个
        m_waiterLock.Set();
    }
}

View Code

Microsoft.AspNet.Identity.Core      MSDN评释:包括与治本 ASP.NET
Identity 的用户和剧中人物相关的类和接口。

Microsoft.AspNet.Identity.Core      MSDN证明:包蕴与治本 ASP.NET
Identity 的用户和剧中人物相关的类和接口。

FCL中的混合方式

马努alReset伊夫ntSlim、SemaphoreSlim使用上和基础情势1致,只是都在用户格局中自旋,并且都以在放生第一遍竞争时,创造基础情势对象。并且能够经过CancellationToken实行中断退出。

bf88必发唯一官网 40bf88必发唯一官网 41

static void Main(string[] args)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    int sum = 0;
    SemaphoreSlim g = new SemaphoreSlim(1);
    var t1 = Task.Run(() =>
    {
        for (int i = 0; i < 3000000; i++)
        {
            g.Wait();
            sum += i;
            g.Release();
        }
    });
    var t2 = Task.Run(() =>
    {
        for (int i = 3000000; i < 5000000; i++)
        {
            g.Wait();
            sum += i;
            g.Release();
        }
    });

    Task.WaitAll(t1, t2);
    Console.WriteLine("和:" + sum);
    Console.WriteLine("用时:" + watch.ElapsedMilliseconds);
}

View Code

和:1642668640

用时:1267

请按放四键继续. . .

(音讯消息参考:)

(音信音信参考:)

Monitor

 保存在堆上的对象都有一个同步索引块,暗中认可意况下同步索引块值为一,并且CLTucson先导化时在堆中分配3个共同数组,调用Monitor.Enter方法时,要是目的同步索引块为1(否则,等待),那么CLRAV4在数组中找到3个空白块,并安装对象的联名块索引,让它引用该联合块,调用Exit方法时,会检讨是还是不是有其余线程正在等候使用这么些合伙块,未有的话,就把同步索引块重新安装为1,有的话就让等待的线程进苏醒。Enter的第三个参数表示境况,使用的时候,设置三个暗许的false,假诺竞态成功,那么就改为true.

bf88必发唯一官网 42bf88必发唯一官网 43

public static class Monitor
{
    public static void Enter(object obj);
    public static void Enter(object obj, ref bool lockTaken);
    public static void Exit(object obj);
    public static bool IsEntered(object obj);
    public static void Pulse(object obj);
    public static void PulseAll(object obj);
    public static void TryEnter(object obj, int millisecondsTimeout, ref bool lockTaken);
    public static bool Wait(object obj, int millisecondsTimeout, bool exitContext);
}
private static readonly object ObjAsync = new object();
static void Main(string[] args)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    int sum = 0;
    var t1 = Task.Run(() =>
    {
        for (int i = 0; i < 3000000; i++)
        {
            Monitor.Enter(ObjAsync);
                sum += i;
            Monitor.Exit(ObjAsync);

        }
    });
    var t2 = Task.Run(() =>
    {
        for (int i = 3000000; i < 5000000; i++)
        {
            Monitor.Enter(ObjAsync);
            sum += i;
            Monitor.Exit(ObjAsync);

        }
    });
    Task.WaitAll(t1, t2);
    Console.WriteLine("和:" + sum);
    Console.WriteLine("用时:" + watch.ElapsedMilliseconds);
}

View Code

和:1642668640

用时:337

请按任性键继续. . .

从MSDN的申明可以看出来Microsoft.AspNet.Identity.Owin里实际正是将网址的登入、注册职业场景所需的API进行了打包;

从MSDN的注释能够看出来Microsoft.AspNet.Identity.Owin里实际正是将网址的记名、注册专门的学问场景所需的API进行了包装;

ReaderWriterLockSlim读写锁分离

ReaderWriterLockSlim用来提供读写锁分离,前边介绍的锁,四个线程同时访问共享数据时,线程竞争失利是都会卡住,产生应用程序的紧缩性和吞吐才具下落。假诺拥有线程只以读的措施访问数据,根本未曾供给阻塞他们,应该允许出现的走访数据。

bf88必发唯一官网 44bf88必发唯一官网 45

public class ReaderWriterLockSlim : IDisposable
{
    public ReaderWriterLockSlim();
    public ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy);

    public int WaitingReadCount { get; }
    public int RecursiveWriteCount { get; }
    public int RecursiveUpgradeCount { get; }
    public int RecursiveReadCount { get; }
    public int CurrentReadCount { get; }
    public LockRecursionPolicy RecursionPolicy { get; }
    public bool IsWriteLockHeld { get; }
    public bool IsUpgradeableReadLockHeld { get; }
    public bool IsReadLockHeld { get; }
    public int WaitingUpgradeCount { get; }
    public int WaitingWriteCount { get; }

    public void Dispose();
    public void EnterReadLock();
    public void EnterUpgradeableReadLock();
    public void EnterWriteLock();
    public void ExitReadLock();
    public void ExitUpgradeableReadLock();
    public void ExitWriteLock();
    public bool TryEnterReadLock(int millisecondsTimeout);
    public bool TryEnterUpgradeableReadLock(int millisecondsTimeout);
    public bool TryEnterWriteLock(int millisecondsTimeout);

}

View Code

 使用方法。构造函数中1旦枚举为SupportsRecursion表示补助递归

bf88必发唯一官网 46bf88必发唯一官网 47

static void Main(string[] args)
{
    Stopwatch watch = new Stopwatch();
    watch.Start();

    ReaderWriterLockSlim lo = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
    int sum = 0;
    var t1 = Task.Run(() =>
    {
        for (int i = 0; i < 3000000; i++)
        {
            lo.EnterWriteLock();
                sum += i;
            lo.ExitWriteLock();

        }
    });
    var t2 = Task.Run(() =>
    {
        for (int i = 3000000; i < 5000000; i++)
        {
            lo.EnterWriteLock();
            sum += i;
            lo.ExitWriteLock();

        }
    });
    Task.WaitAll(t1, t2);
    Console.WriteLine("和:" + sum);
    Console.WriteLine("用时:" + watch.ElapsedMilliseconds);
}

View Code

和:1642668640

用时:622

请按任意键继续. . .

第三部、建模

第三部、建模

双锁技巧(单例格局)

 可能会有人认为怎么lock外已经看清了_instance不为null了,为何还要判别?

或是会有三个线程同时经过第2个if决断,然后唯有多个线程进入了lock内部,创立完结未有失常态,可是原先等待的线程就进入了,假使未有第3个if,他就再次创下设了一个目的!!!

bf88必发唯一官网 48bf88必发唯一官网 49

class Singleton
{
    private static object s_lock = new object();

    private static Singleton _instance = null;

    private Singleton() { }

    public static Singleton GetSingleTon()
    {
        if (_instance != null) return _instance;

        lock (s_lock)
        {
            if(_instance == null)
            {
                Singleton temp = new Singleton();
                Volatile.Write(ref _instance, temp);
            }
        }
        return _instance;
    }
}

View Code

如自个儿未来的数据库的用户表为BASE_USE宝马X3,表结构如下

如自己明日的数据库的用户表为BASE_USETiggo,表结构如下

小结

那1节学习了.net中的各样锁,Monitor认定时使用的最多的,不过某些时候,恐怕需求具体分析吧,举例在MVC中的路由的读取,由于路由是程序运维的时候初叶化的(只有3次),所以利用了ReaderWriterLockSlim来提用读写锁分离的方式,又举个例子说MVC中封装的AsyncResultWrapper是选取Monitor和Interlocked结合的办法来开展线程同步的。那1篇真的好长啊。鼓励一下投机,加油,嘿嘿!!

 

 

 

 

CREATE TABLE [dbo].[BASE_USER](
    [ID] [uniqueidentifier] NOT NULL PRIMARY KEY,
    [NAME] [varchar](50) NOT NULL,
    [PWD] [varchar](50) NOT NULL,
) ON [PRIMARY]
CREATE TABLE [dbo].[BASE_USER](
    [ID] [uniqueidentifier] NOT NULL PRIMARY KEY,
    [NAME] [varchar](50) NOT NULL,
    [PWD] [varchar](50) NOT NULL,
) ON [PRIMARY]

  

  

大家在工程站点的Models文件夹里新建3个BASE_USE福睿斯类,让它继续Microsoft.AspNet.Identity.IUser<GUID>,这里我们加三个数据表不设有的NICKNAME别名字段,到背后看看会有哪些效劳~

咱们在工程站点的Models文件夹里新建多个BASE_USERubicon类,让它继续Microsoft.AspNet.Identity.IUser<GUID>,这里咱们加2个数据表不设有的NICKNAME别名字段,到背后看看会有怎样效益~

bf88必发唯一官网 50bf88必发唯一官网 51

bf88必发唯一官网 52bf88必发唯一官网 53

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 
 6 namespace IdeintityDemo.Models
 7 {
 8     public class BASE_USER : Microsoft.AspNet.Identity.IUser<Guid>
 9     {
10         /// <summary>
11         /// 用户编号
12         /// </summary>
13         public Guid Id { get; set; }
14         /// <summary>
15         /// 用户名
16         /// </summary>
17         public string UserName { get; set; }
18         /// <summary>
19         /// 密码
20         /// </summary>
21         public string PWD { get; set; }
22         /// <summary>
23         /// 昵称
24         /// </summary>
25         public string NickName { get; set; }
26 
27         public bool RememberMe { get; set; }
28     }
29 }
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 
 6 namespace IdeintityDemo.Models
 7 {
 8     public class BASE_USER : Microsoft.AspNet.Identity.IUser<Guid>
 9     {
10         /// <summary>
11         /// 用户编号
12         /// </summary>
13         public Guid Id { get; set; }
14         /// <summary>
15         /// 用户名
16         /// </summary>
17         public string UserName { get; set; }
18         /// <summary>
19         /// 密码
20         /// </summary>
21         public string PWD { get; set; }
22         /// <summary>
23         /// 昵称
24         /// </summary>
25         public string NickName { get; set; }
26 
27         public bool RememberMe { get; set; }
28     }
29 }

View Code

View Code

 

 

第5部
创立UserStore类,该类通过接二连三接口IUserStore来实现用户存款和储蓄在数据库的api

第6部
创设UserStore类,该类通过持续接口IUserStore来达成用户存款和储蓄在数据库的api

bf88必发唯一官网 54bf88必发唯一官网 55

bf88必发唯一官网 56bf88必发唯一官网 57

  1 using Microsoft.AspNet.Identity;
  2 using System;
  3 using System.Collections.Generic;
  4 using System.Data;
  5 using System.Data.SqlClient;
  6 using System.Linq;
  7 using System.Threading.Tasks;
  8 using System.Web;
  9 using System.Security.Claims;
 10 using IdeintityDemo.Models;
 11 using IdeintityDemo.Common;
 12 
 13 namespace IdeintityDemo.Identity
 14 {
 15 
 16     /// <summary>
 17     /// 用户持久化存储对象
 18     /// 必须实现Microsoft.AspNet.Identity相应接口,否则在SignInManager类进行登录校验过程中
 19     /// 会弹出未实现相关接口的异常!   
 20     /// IUserStore:检测是否存在账户
 21     /// IUserPasswordStore:校验密码
 22     /// IUserLockoutStore:锁定账户相关操作
 23     /// IUserClaimStore:存储用户特定的声明
 24     /// IUserEmailStore:邮箱关联、验证等相关操作
 25     /// IUserPhoneNumberStore:手机关联、验证相关操作
 26     /// IUserTwoFactorStore:获取或设置用户双重身份验证的方法。
 27     /// </summary>
 28     public class HsUserStore : Microsoft.AspNet.Identity.IUserStore<BASE_USER, Guid>,
 29                                Microsoft.AspNet.Identity.IUserPasswordStore<BASE_USER, Guid>,
 30                                Microsoft.AspNet.Identity.IUserLockoutStore<BASE_USER, Guid>,
 31                                Microsoft.AspNet.Identity.IUserClaimStore<BASE_USER, Guid>,
 32                                Microsoft.AspNet.Identity.IUserEmailStore<BASE_USER, Guid>,
 33                                Microsoft.AspNet.Identity.IUserPhoneNumberStore<BASE_USER, Guid>,
 34                                Microsoft.AspNet.Identity.IUserTwoFactorStore<BASE_USER, Guid>
 35     {
 36 
 37         /// <summary>
 38         /// 声明
 39         /// </summary>
 40         public IList<System.Security.Claims.Claim> Claims = null;
 41         /// <summary>
 42         /// 用户
 43         /// </summary>
 44         public BASE_USER UserIdentity = null;
 45 
 46         /// <summary>
 47         /// 实例化
 48         /// </summary>
 49         public HsUserStore()
 50         {
 51             //声明
 52             Claims = new List<System.Security.Claims.Claim>();
 53         }
 54         /// <summary>
 55         /// 创建用户
 56         /// </summary>
 57         /// <param name="user"></param>
 58         /// <returns></returns>
 59         public Task CreateAsync(BASE_USER user)
 60         {
 61             return Task.Run(() => {
 62                 string sql = @"INSERT INTO [dbo].[BASE_USER]([ID],[NAME],[PWD])
 63                         VALUES(@UserID,@name,@pwd)";
 64                 SqlParameter[] parameters = {
 65                      new SqlParameter("@UserID", Guid.NewGuid()),
 66                      new SqlParameter("@name", user.UserName),
 67                      new SqlParameter("@pwd", user.PWD)
 68                 };
 69                 int iResult = DbHelperSQL.ExecuteSql(sql, parameters);
 70             });
 71         }
 72         /// <summary>
 73         /// 删除用户
 74         /// </summary>
 75         /// <param name="user"></param>
 76         /// <returns></returns>
 77         public Task DeleteAsync(BASE_USER user)
 78         {
 79             return Task.Run(() => {
 80                 string sql = @"DELETE FROM [dbo].[BASE_USER] WHERE ID=@ID";
 81                 SqlParameter[] parameters = {
 82                      new SqlParameter("@UserID", user.Id)};
 83                 int iResult = DbHelperSQL.ExecuteSql(sql, parameters);
 84             });
 85         }
 86         /// <summary>
 87         /// 根据用户id获取用户
 88         /// </summary>
 89         /// <param name="userId"></param>
 90         /// <returns></returns>
 91         public Task<BASE_USER> FindByIdAsync(Guid userId)
 92         {
 93             return Task<BASE_USER>.Run(() =>
 94              {
 95                  BASE_USER result = new BASE_USER();
 96                  string sql = @"SELECT * FROM [dbo].[BASE_USER] WHERE ID=@ID";
 97                  SqlParameter[] parameters = {
 98                      new SqlParameter("@ID", userId)};
 99                  DataSet ds = DbHelperSQL.Query(sql, parameters);
100                  if (ds == null || ds.Tables == null || ds.Tables[0].Rows.Count <= 0)
101                      return result;
102                  //model
103                  DataRow dr = ds.Tables[0].Rows[0];
104                  result.Id = Guid.Parse(dr["ID"].ToString());
105                  result.UserName = dr["NAME"].ToString();
106                  result.PWD = dr["PWD"].ToString();
107                  return result;
108              });
109         }
110         /// <summary>
111         /// 根据名称获取用户信息
112         /// </summary>
113         /// <param name="userName"></param>
114         /// <returns></returns>
115         public Task<BASE_USER> FindByNameAsync(string userName)
116         {
117             return Task<BASE_USER>.Run(() =>
118             {
119                 BASE_USER result = new BASE_USER();
120                 string sql = @"SELECT * FROM [dbo].[BASE_USER] WHERE NAME=@NAME";
121                 SqlParameter[] parameters = {
122                      new SqlParameter("@NAME", userName)};
123                 DataSet ds = DbHelperSQL.Query(sql, parameters);
124                 if (ds == null || ds.Tables == null || ds.Tables[0].Rows.Count <= 0)
125                     return result;
126                 //model
127                 DataRow dr = ds.Tables[0].Rows[0];
128                 result.Id = Guid.Parse(dr["ID"].ToString());
129                 result.UserName = dr["NAME"].ToString();
130                 result.PWD = dr["PWD"].ToString();
131 
132                 return result;
133             });
134         }
135         /// <summary>
136         /// 更新用户
137         /// </summary>
138         /// <param name="user"></param>
139         /// <returns></returns>
140         public Task UpdateAsync(BASE_USER user)
141         {
142             return Task.Run(() =>
143             {
144                 //省略...
145             });
146         }
147         /// <summary>
148         /// 异步返回当前失败的访问尝试次数。当密码被验证或帐户被锁定时,这个数字通常会被重置。
149         /// (这里因为我数据库里没有去做这一块的记录保存,所以先写死返回1)
150         /// </summary>
151         /// <param name="user">用户</param>
152         /// <returns></returns>
153         public Task<int> GetAccessFailedCountAsync(BASE_USER user)
154         {
155             return Task.FromResult<int>(1);
156         }
157         /// <summary>
158         /// 获取锁定状态
159         /// </summary>
160         /// <param name="user"></param>
161         /// <returns></returns>
162         public Task<bool> GetLockoutEnabledAsync(BASE_USER user)
163         {
164             return Task.FromResult<bool>(false);
165         }
166         /// <summary>
167         /// 获取锁定结束时间
168         /// </summary>
169         /// <param name="user"></param>
170         /// <returns></returns>
171         public Task<DateTimeOffset> GetLockoutEndDateAsync(BASE_USER user)
172         {
173             throw new NotImplementedException();
174         }
175         /// <summary>
176         /// 记录试图访问用户失败的记录。
177         /// </summary>
178         /// <param name="user"></param>
179         /// <returns></returns>
180         public Task<int> IncrementAccessFailedCountAsync(BASE_USER user)
181         {
182             return Task.FromResult<int>(1);
183         }
184         /// <summary>
185         /// 重置访问失败计数,通常在帐户成功访问之后
186         /// </summary>
187         /// <param name="user"></param>
188         /// <returns></returns>
189         public Task ResetAccessFailedCountAsync(BASE_USER user)
190         {
191             return Task.FromResult(false);
192         }
193         /// <summary>
194         /// 异步设置是否可以锁定用户。
195         /// </summary>
196         /// <param name="user"></param>
197         /// <param name="enabled"></param>
198         /// <returns></returns>
199         public Task SetLockoutEnabledAsync(BASE_USER user, bool enabled)
200         {
201             return Task.Run(() => { });
202         }
203         /// <summary>
204         /// 异步锁定用户直到指定的结束日期
205         /// </summary>
206         /// <param name="user"></param>
207         /// <param name="lockoutEnd"></param>
208         /// <returns></returns>
209         public Task SetLockoutEndDateAsync(BASE_USER user, DateTimeOffset lockoutEnd)
210         {
211             return Task.Run(() =>
212             {
213 
214             });
215         }
216         /// <summary>
217         /// 获取用户密码
218         /// </summary>
219         /// <param name="user"></param>
220         /// <returns></returns>
221         public Task<string> GetPasswordHashAsync(BASE_USER user)
222         {
223             return Task<string>.Run(() =>
224             {
225                 return user.PWD;
226             });
227         }
228         /// <summary>
229         /// 是否有密码
230         /// </summary>
231         /// <param name="user"></param>
232         /// <returns></returns>
233         public Task<bool> HasPasswordAsync(BASE_USER user)
234         {
235             return Task.FromResult<bool>(!string.IsNullOrEmpty(user.PWD));
236         }
237         /// <summary>
238         /// 密码进行加密
239         /// </summary>
240         /// <param name="user"></param>
241         /// <param name="passwordHash"></param>
242         /// <returns></returns>
243         public Task SetPasswordHashAsync(BASE_USER user, string passwordHash)
244         {
245             return Task.Run(() =>
246             {
247                 user.PWD = passwordHash;//加密后
248             });
249         }
250         /// <summary>
251         /// 添加一个声明
252         /// </summary>
253         /// <param name="user"></param>
254         /// <param name="claim"></param>
255         /// <returns></returns>
256         public Task AddClaimAsync(BASE_USER user, Claim claim)
257         {
258             return Task.Run(() => { Claims.Add(claim); });
259         }
260         /// <summary>
261         /// 获取改用户的所有声明
262         /// </summary>
263         /// <param name="user"></param>
264         /// <returns></returns>
265         public Task<IList<Claim>> GetClaimsAsync(BASE_USER user)
266         {
267             return Task.Run<IList<System.Security.Claims.Claim>>(() =>
268             {
269                 IList<System.Security.Claims.Claim> list = new List<System.Security.Claims.Claim>();
270                 return list;
271             });
272         }
273         /// <summary>
274         /// 移除申明
275         /// </summary>
276         /// <param name="user"></param>
277         /// <param name="claim"></param>
278         /// <returns></returns>
279         public Task RemoveClaimAsync(BASE_USER user, Claim claim)
280         {
281             return Task.Run(() =>
282             {
283 
284             });
285         }
286         /// <summary>
287         /// 通过邮箱获取对应的用户信息
288         /// </summary>
289         /// <param name="email"></param>
290         /// <returns></returns>
291         public Task<BASE_USER> FindByEmailAsync(string email)
292         {
293             return Task<BASE_USER>.Run(() => new BASE_USER());
294         }
295         /// <summary>
296         /// 获取邮箱
297         /// </summary>
298         /// <param name="user"></param>
299         /// <returns></returns>
300         public Task<string> GetEmailAsync(BASE_USER user)
301         {
302             return Task<string>.Run(() => string.Empty);
303         }
304         /// <summary>
305         /// 确认邮箱
306         /// </summary>
307         /// <param name="user"></param>
308         /// <returns></returns>
309         public Task<bool> GetEmailConfirmedAsync(BASE_USER user)
310         {
311             return Task.FromResult<bool>(true);
312         }
313         /// <summary>
314         /// 修改邮箱
315         /// </summary>
316         /// <param name="user"></param>
317         /// <param name="email"></param>
318         /// <returns></returns>
319         public Task SetEmailAsync(BASE_USER user, string email)
320         {
321             return Task.Run(() => { });
322         }
323         /// <summary>
324         ///设置用户是否邮箱确认 
325         /// </summary>
326         /// <param name="user"></param>
327         /// <param name="confirmed"></param>
328         /// <returns></returns>
329         public Task SetEmailConfirmedAsync(BASE_USER user, bool confirmed)
330         {
331             throw new NotImplementedException();
332         }
333         /// <summary>
334         /// 获取联系电话
335         /// </summary>
336         /// <param name="user"></param>
337         /// <returns></returns>
338         public Task<string> GetPhoneNumberAsync(BASE_USER user)
339         {
340             return Task.FromResult<string>(string.Empty);
341         }
342         /// <summary>
343         /// 获取用户电话号码是否已确认
344         /// </summary>
345         /// <param name="user"></param>
346         /// <returns></returns>
347         public Task<bool> GetPhoneNumberConfirmedAsync(BASE_USER user)
348         {
349             return Task.FromResult<bool>(true);
350         }
351         /// <summary>
352         /// 设置用户电话号码
353         /// </summary>
354         /// <param name="user"></param>
355         /// <param name="phoneNumber"></param>
356         /// <returns></returns>
357         public Task SetPhoneNumberAsync(BASE_USER user, string phoneNumber)
358         {
359             return Task.Run(() => { });
360         }
361         /// <summary>
362         /// 设置与用户关联的电话号码
363         /// </summary>
364         /// <param name="user"></param>
365         /// <param name="confirmed"></param>
366         /// <returns></returns>
367         public Task SetPhoneNumberConfirmedAsync(BASE_USER user, bool confirmed)
368         {
369             return Task.Run(() => { });
370         }
371         /// <summary>
372         /// 是否为用户启用了双重身份验证。
373         /// </summary>
374         /// <param name="user"></param>
375         /// <returns></returns>
376         public Task<bool> GetTwoFactorEnabledAsync(BASE_USER user)
377         {
378             return Task.FromResult<bool>(false);
379         }
380         /// <summary>
381         /// 设置双重身份验证
382         /// </summary>
383         /// <param name="user"></param>
384         /// <param name="enabled"></param>
385         /// <returns></returns>
386         public Task SetTwoFactorEnabledAsync(BASE_USER user, bool enabled)
387         {
388             throw new NotImplementedException();
389         }
390         /// <summary>
391         /// 释放
392         /// </summary>
393         public void Dispose()
394         {
395             throw new NotImplementedException();
396         }
397 
398     }
399 }
  1 using Microsoft.AspNet.Identity;
  2 using System;
  3 using System.Collections.Generic;
  4 using System.Data;
  5 using System.Data.SqlClient;
  6 using System.Linq;
  7 using System.Threading.Tasks;
  8 using System.Web;
  9 using System.Security.Claims;
 10 using IdeintityDemo.Models;
 11 using IdeintityDemo.Common;
 12 
 13 namespace IdeintityDemo.Identity
 14 {
 15 
 16     /// <summary>
 17     /// 用户持久化存储对象
 18     /// 必须实现Microsoft.AspNet.Identity相应接口,否则在SignInManager类进行登录校验过程中
 19     /// 会弹出未实现相关接口的异常!   
 20     /// IUserStore:检测是否存在账户
 21     /// IUserPasswordStore:校验密码
 22     /// IUserLockoutStore:锁定账户相关操作
 23     /// IUserClaimStore:存储用户特定的声明
 24     /// IUserEmailStore:邮箱关联、验证等相关操作
 25     /// IUserPhoneNumberStore:手机关联、验证相关操作
 26     /// IUserTwoFactorStore:获取或设置用户双重身份验证的方法。
 27     /// </summary>
 28     public class HsUserStore : Microsoft.AspNet.Identity.IUserStore<BASE_USER, Guid>,
 29                                Microsoft.AspNet.Identity.IUserPasswordStore<BASE_USER, Guid>,
 30                                Microsoft.AspNet.Identity.IUserLockoutStore<BASE_USER, Guid>,
 31                                Microsoft.AspNet.Identity.IUserClaimStore<BASE_USER, Guid>,
 32                                Microsoft.AspNet.Identity.IUserEmailStore<BASE_USER, Guid>,
 33                                Microsoft.AspNet.Identity.IUserPhoneNumberStore<BASE_USER, Guid>,
 34                                Microsoft.AspNet.Identity.IUserTwoFactorStore<BASE_USER, Guid>
 35     {
 36 
 37         /// <summary>
 38         /// 声明
 39         /// </summary>
 40         public IList<System.Security.Claims.Claim> Claims = null;
 41         /// <summary>
 42         /// 用户
 43         /// </summary>
 44         public BASE_USER UserIdentity = null;
 45 
 46         /// <summary>
 47         /// 实例化
 48         /// </summary>
 49         public HsUserStore()
 50         {
 51             //声明
 52             Claims = new List<System.Security.Claims.Claim>();
 53         }
 54         /// <summary>
 55         /// 创建用户
 56         /// </summary>
 57         /// <param name="user"></param>
 58         /// <returns></returns>
 59         public Task CreateAsync(BASE_USER user)
 60         {
 61             return Task.Run(() => {
 62                 string sql = @"INSERT INTO [dbo].[BASE_USER]([ID],[NAME],[PWD])
 63                         VALUES(@UserID,@name,@pwd)";
 64                 SqlParameter[] parameters = {
 65                      new SqlParameter("@UserID", Guid.NewGuid()),
 66                      new SqlParameter("@name", user.UserName),
 67                      new SqlParameter("@pwd", user.PWD)
 68                 };
 69                 int iResult = DbHelperSQL.ExecuteSql(sql, parameters);
 70             });
 71         }
 72         /// <summary>
 73         /// 删除用户
 74         /// </summary>
 75         /// <param name="user"></param>
 76         /// <returns></returns>
 77         public Task DeleteAsync(BASE_USER user)
 78         {
 79             return Task.Run(() => {
 80                 string sql = @"DELETE FROM [dbo].[BASE_USER] WHERE ID=@ID";
 81                 SqlParameter[] parameters = {
 82                      new SqlParameter("@UserID", user.Id)};
 83                 int iResult = DbHelperSQL.ExecuteSql(sql, parameters);
 84             });
 85         }
 86         /// <summary>
 87         /// 根据用户id获取用户
 88         /// </summary>
 89         /// <param name="userId"></param>
 90         /// <returns></returns>
 91         public Task<BASE_USER> FindByIdAsync(Guid userId)
 92         {
 93             return Task<BASE_USER>.Run(() =>
 94              {
 95                  BASE_USER result = new BASE_USER();
 96                  string sql = @"SELECT * FROM [dbo].[BASE_USER] WHERE ID=@ID";
 97                  SqlParameter[] parameters = {
 98                      new SqlParameter("@ID", userId)};
 99                  DataSet ds = DbHelperSQL.Query(sql, parameters);
100                  if (ds == null || ds.Tables == null || ds.Tables[0].Rows.Count <= 0)
101                      return result;
102                  //model
103                  DataRow dr = ds.Tables[0].Rows[0];
104                  result.Id = Guid.Parse(dr["ID"].ToString());
105                  result.UserName = dr["NAME"].ToString();
106                  result.PWD = dr["PWD"].ToString();
107                  return result;
108              });
109         }
110         /// <summary>
111         /// 根据名称获取用户信息
112         /// </summary>
113         /// <param name="userName"></param>
114         /// <returns></returns>
115         public Task<BASE_USER> FindByNameAsync(string userName)
116         {
117             return Task<BASE_USER>.Run(() =>
118             {
119                 BASE_USER result = new BASE_USER();
120                 string sql = @"SELECT * FROM [dbo].[BASE_USER] WHERE NAME=@NAME";
121                 SqlParameter[] parameters = {
122                      new SqlParameter("@NAME", userName)};
123                 DataSet ds = DbHelperSQL.Query(sql, parameters);
124                 if (ds == null || ds.Tables == null || ds.Tables[0].Rows.Count <= 0)
125                     return result;
126                 //model
127                 DataRow dr = ds.Tables[0].Rows[0];
128                 result.Id = Guid.Parse(dr["ID"].ToString());
129                 result.UserName = dr["NAME"].ToString();
130                 result.PWD = dr["PWD"].ToString();
131 
132                 return result;
133             });
134         }
135         /// <summary>
136         /// 更新用户
137         /// </summary>
138         /// <param name="user"></param>
139         /// <returns></returns>
140         public Task UpdateAsync(BASE_USER user)
141         {
142             return Task.Run(() =>
143             {
144                 //省略...
145             });
146         }
147         /// <summary>
148         /// 异步返回当前失败的访问尝试次数。当密码被验证或帐户被锁定时,这个数字通常会被重置。
149         /// (这里因为我数据库里没有去做这一块的记录保存,所以先写死返回1)
150         /// </summary>
151         /// <param name="user">用户</param>
152         /// <returns></returns>
153         public Task<int> GetAccessFailedCountAsync(BASE_USER user)
154         {
155             return Task.FromResult<int>(1);
156         }
157         /// <summary>
158         /// 获取锁定状态
159         /// </summary>
160         /// <param name="user"></param>
161         /// <returns></returns>
162         public Task<bool> GetLockoutEnabledAsync(BASE_USER user)
163         {
164             return Task.FromResult<bool>(false);
165         }
166         /// <summary>
167         /// 获取锁定结束时间
168         /// </summary>
169         /// <param name="user"></param>
170         /// <returns></returns>
171         public Task<DateTimeOffset> GetLockoutEndDateAsync(BASE_USER user)
172         {
173             throw new NotImplementedException();
174         }
175         /// <summary>
176         /// 记录试图访问用户失败的记录。
177         /// </summary>
178         /// <param name="user"></param>
179         /// <returns></returns>
180         public Task<int> IncrementAccessFailedCountAsync(BASE_USER user)
181         {
182             return Task.FromResult<int>(1);
183         }
184         /// <summary>
185         /// 重置访问失败计数,通常在帐户成功访问之后
186         /// </summary>
187         /// <param name="user"></param>
188         /// <returns></returns>
189         public Task ResetAccessFailedCountAsync(BASE_USER user)
190         {
191             return Task.FromResult(false);
192         }
193         /// <summary>
194         /// 异步设置是否可以锁定用户。
195         /// </summary>
196         /// <param name="user"></param>
197         /// <param name="enabled"></param>
198         /// <returns></returns>
199         public Task SetLockoutEnabledAsync(BASE_USER user, bool enabled)
200         {
201             return Task.Run(() => { });
202         }
203         /// <summary>
204         /// 异步锁定用户直到指定的结束日期
205         /// </summary>
206         /// <param name="user"></param>
207         /// <param name="lockoutEnd"></param>
208         /// <returns></returns>
209         public Task SetLockoutEndDateAsync(BASE_USER user, DateTimeOffset lockoutEnd)
210         {
211             return Task.Run(() =>
212             {
213 
214             });
215         }
216         /// <summary>
217         /// 获取用户密码
218         /// </summary>
219         /// <param name="user"></param>
220         /// <returns></returns>
221         public Task<string> GetPasswordHashAsync(BASE_USER user)
222         {
223             return Task<string>.Run(() =>
224             {
225                 return user.PWD;
226             });
227         }
228         /// <summary>
229         /// 是否有密码
230         /// </summary>
231         /// <param name="user"></param>
232         /// <returns></returns>
233         public Task<bool> HasPasswordAsync(BASE_USER user)
234         {
235             return Task.FromResult<bool>(!string.IsNullOrEmpty(user.PWD));
236         }
237         /// <summary>
238         /// 密码进行加密
239         /// </summary>
240         /// <param name="user"></param>
241         /// <param name="passwordHash"></param>
242         /// <returns></returns>
243         public Task SetPasswordHashAsync(BASE_USER user, string passwordHash)
244         {
245             return Task.Run(() =>
246             {
247                 user.PWD = passwordHash;//加密后
248             });
249         }
250         /// <summary>
251         /// 添加一个声明
252         /// </summary>
253         /// <param name="user"></param>
254         /// <param name="claim"></param>
255         /// <returns></returns>
256         public Task AddClaimAsync(BASE_USER user, Claim claim)
257         {
258             return Task.Run(() => { Claims.Add(claim); });
259         }
260         /// <summary>
261         /// 获取改用户的所有声明
262         /// </summary>
263         /// <param name="user"></param>
264         /// <returns></returns>
265         public Task<IList<Claim>> GetClaimsAsync(BASE_USER user)
266         {
267             return Task.Run<IList<System.Security.Claims.Claim>>(() =>
268             {
269                 IList<System.Security.Claims.Claim> list = new List<System.Security.Claims.Claim>();
270                 return list;
271             });
272         }
273         /// <summary>
274         /// 移除申明
275         /// </summary>
276         /// <param name="user"></param>
277         /// <param name="claim"></param>
278         /// <returns></returns>
279         public Task RemoveClaimAsync(BASE_USER user, Claim claim)
280         {
281             return Task.Run(() =>
282             {
283 
284             });
285         }
286         /// <summary>
287         /// 通过邮箱获取对应的用户信息
288         /// </summary>
289         /// <param name="email"></param>
290         /// <returns></returns>
291         public Task<BASE_USER> FindByEmailAsync(string email)
292         {
293             return Task<BASE_USER>.Run(() => new BASE_USER());
294         }
295         /// <summary>
296         /// 获取邮箱
297         /// </summary>
298         /// <param name="user"></param>
299         /// <returns></returns>
300         public Task<string> GetEmailAsync(BASE_USER user)
301         {
302             return Task<string>.Run(() => string.Empty);
303         }
304         /// <summary>
305         /// 确认邮箱
306         /// </summary>
307         /// <param name="user"></param>
308         /// <returns></returns>
309         public Task<bool> GetEmailConfirmedAsync(BASE_USER user)
310         {
311             return Task.FromResult<bool>(true);
312         }
313         /// <summary>
314         /// 修改邮箱
315         /// </summary>
316         /// <param name="user"></param>
317         /// <param name="email"></param>
318         /// <returns></returns>
319         public Task SetEmailAsync(BASE_USER user, string email)
320         {
321             return Task.Run(() => { });
322         }
323         /// <summary>
324         ///设置用户是否邮箱确认 
325         /// </summary>
326         /// <param name="user"></param>
327         /// <param name="confirmed"></param>
328         /// <returns></returns>
329         public Task SetEmailConfirmedAsync(BASE_USER user, bool confirmed)
330         {
331             throw new NotImplementedException();
332         }
333         /// <summary>
334         /// 获取联系电话
335         /// </summary>
336         /// <param name="user"></param>
337         /// <returns></returns>
338         public Task<string> GetPhoneNumberAsync(BASE_USER user)
339         {
340             return Task.FromResult<string>(string.Empty);
341         }
342         /// <summary>
343         /// 获取用户电话号码是否已确认
344         /// </summary>
345         /// <param name="user"></param>
346         /// <returns></returns>
347         public Task<bool> GetPhoneNumberConfirmedAsync(BASE_USER user)
348         {
349             return Task.FromResult<bool>(true);
350         }
351         /// <summary>
352         /// 设置用户电话号码
353         /// </summary>
354         /// <param name="user"></param>
355         /// <param name="phoneNumber"></param>
356         /// <returns></returns>
357         public Task SetPhoneNumberAsync(BASE_USER user, string phoneNumber)
358         {
359             return Task.Run(() => { });
360         }
361         /// <summary>
362         /// 设置与用户关联的电话号码
363         /// </summary>
364         /// <param name="user"></param>
365         /// <param name="confirmed"></param>
366         /// <returns></returns>
367         public Task SetPhoneNumberConfirmedAsync(BASE_USER user, bool confirmed)
368         {
369             return Task.Run(() => { });
370         }
371         /// <summary>
372         /// 是否为用户启用了双重身份验证。
373         /// </summary>
374         /// <param name="user"></param>
375         /// <returns></returns>
376         public Task<bool> GetTwoFactorEnabledAsync(BASE_USER user)
377         {
378             return Task.FromResult<bool>(false);
379         }
380         /// <summary>
381         /// 设置双重身份验证
382         /// </summary>
383         /// <param name="user"></param>
384         /// <param name="enabled"></param>
385         /// <returns></returns>
386         public Task SetTwoFactorEnabledAsync(BASE_USER user, bool enabled)
387         {
388             throw new NotImplementedException();
389         }
390         /// <summary>
391         /// 释放
392         /// </summary>
393         public void Dispose()
394         {
395             throw new NotImplementedException();
396         }
397 
398     }
399 }

View Code

View Code

 

 

 

 

第伍步承袭UserManager类

第6步承继UserManager类

bf88必发唯一官网 58bf88必发唯一官网 59

bf88必发唯一官网 60bf88必发唯一官网 61

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using IdeintityDemo.Models;
 6 using Microsoft.AspNet.Identity;
 7 
 8 namespace IdeintityDemo.Identity
 9 {
10     public class HsUserManager:UserManager<BASE_USER,Guid>
11     {
12         /// <summary>
13         /// 通过构造函数注入用户存储实现类
14         /// </summary>
15         /// <param name="store"></param>
16         public HsUserManager(HsUserStore store) : base(store)
17         {
18 
19         }        
20     }
21 }
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using IdeintityDemo.Models;
 6 using Microsoft.AspNet.Identity;
 7 
 8 namespace IdeintityDemo.Identity
 9 {
10     public class HsUserManager:UserManager<BASE_USER,Guid>
11     {
12         /// <summary>
13         /// 通过构造函数注入用户存储实现类
14         /// </summary>
15         /// <param name="store"></param>
16         public HsUserManager(HsUserStore store) : base(store)
17         {
18 
19         }        
20     }
21 }

View Code

View Code

 

 

地点的代码特别特别轻松,不过确很重大,你就知晓为将方面定义的HsUserStore注入到三个IOC容器里就好了。
倘若不流入,你对用户的富有读写db操作都未有,后续一切报到、注册、验证专门的工作都爱莫能助执行!

上边的代码尤其尤其不难,可是确很重视,你就领悟为将地点定义的HsUserStore注入到3个IOC容器里就好了。
如若不流入,你对用户的具备读写db操作都未曾,后续一切报到、注册、验证职业都心有余而力不足实施!

 

 

第伍步承袭SignInManager 类

第四步承接SignInManager 类

 SignInManager类是Microsoft.AspNet.Identity.Owin命名空间下的,集成了用户登入进行管理的相干API,是Asp.Net.Identity里不能缺少的拍卖类

 SignInManager类是Microsoft.AspNet.Identity.Owin命名空间下的,集成了用户登入进行田间处理的相干API,是Asp.Net.Identity里至关重要的拍卖类

我们须求自定义1个登入管理类,承袭SignInManager。

大家要求自定义四个记名管理类,承袭SignInManager。

bf88必发唯一官网 62bf88必发唯一官网 63

bf88必发唯一官网 64bf88必发唯一官网 65

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using IdeintityDemo.Models;
 6 using Microsoft.AspNet.Identity;
 7 using Microsoft.AspNet.Identity.Owin;
 8 using Microsoft.Owin;
 9 using System.Threading.Tasks;
10 using Microsoft.Owin.Security;
11 
12 namespace IdeintityDemo.Identity
13 {
14     /// <summary>
15     /// 登录管理,此处用到了UserManager
16     /// </summary>
17     public class HsSignInManager : SignInManager<BASE_USER, Guid>
18     {
19 
20         /// <summary>
21         /// 构造函数
22         /// </summary>
23         /// <param name="UserManager"></param>
24         /// <param name="AuthenticationManager"></param>
25         public HsSignInManager(Microsoft.AspNet.Identity.UserManager<BASE_USER, Guid> UserManager, Microsoft.Owin.Security.IAuthenticationManager AuthenticationManager)
26             : base(UserManager, AuthenticationManager)
27         {
28 
29         }
30 
31         /// <summary>
32         /// 根据用户名密码,验证用户登录
33         /// </summary>
34         /// <param name="userName"></param>
35         /// <param name="password"></param>
36         /// <param name="isPersistent"></param>
37         /// <param name="shouldLockout"></param>
38         /// <returns></returns>
39         public override System.Threading.Tasks.Task<Microsoft.AspNet.Identity.Owin.SignInStatus> PasswordSignInAsync(string userName,
40                                                                                                                      string password,
41                                                                                                                      bool isPersistent,
42                                                                                                                      bool shouldLockout)
43         {
44             /*这里可以直接通过PasswordSignInAsync来校验,也可以重写~ */
45             //这里用Find方法会返回空的user。。。搞不懂。。
46             var user = base.UserManager.FindByName<BASE_USER, Guid>(userName);
47             if (user == null || user.Id == Guid.Empty)
48                 return Task.FromResult<SignInStatus>(SignInStatus.Failure);
49             else if (user.PWD != password)
50                 return Task.FromResult<SignInStatus>(SignInStatus.Failure);
51             else
52             {
53                 /*这个时候如果不写入到cooks里,在Home控制器的Index action里会被系统的
54                     Authorize刷选器拦截*/
55                 // 利用ASP.NET Identity获取identity 对象
56                 var identity = base.UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
57                 // 将上面拿到的identity对象登录
58                 base.AuthenticationManager.SignIn(new AuthenticationProperties()
59                 { IsPersistent = true }, identity.Result);
60                 return Task.FromResult<SignInStatus>(SignInStatus.Success);
61             }
62             /*这里如果你想直接使用微软的登入方法也可以,直接base.就ok啦*/
63             //return base.PasswordSignInAsync(userName,
64             //                                password,
65             //                                isPersistent,
66             //                                shouldLockout);
67         }
68 
69 
70     }
71 }
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using IdeintityDemo.Models;
 6 using Microsoft.AspNet.Identity;
 7 using Microsoft.AspNet.Identity.Owin;
 8 using Microsoft.Owin;
 9 using System.Threading.Tasks;
10 using Microsoft.Owin.Security;
11 
12 namespace IdeintityDemo.Identity
13 {
14     /// <summary>
15     /// 登录管理,此处用到了UserManager
16     /// </summary>
17     public class HsSignInManager : SignInManager<BASE_USER, Guid>
18     {
19 
20         /// <summary>
21         /// 构造函数
22         /// </summary>
23         /// <param name="UserManager"></param>
24         /// <param name="AuthenticationManager"></param>
25         public HsSignInManager(Microsoft.AspNet.Identity.UserManager<BASE_USER, Guid> UserManager, Microsoft.Owin.Security.IAuthenticationManager AuthenticationManager)
26             : base(UserManager, AuthenticationManager)
27         {
28 
29         }
30 
31         /// <summary>
32         /// 根据用户名密码,验证用户登录
33         /// </summary>
34         /// <param name="userName"></param>
35         /// <param name="password"></param>
36         /// <param name="isPersistent"></param>
37         /// <param name="shouldLockout"></param>
38         /// <returns></returns>
39         public override System.Threading.Tasks.Task<Microsoft.AspNet.Identity.Owin.SignInStatus> PasswordSignInAsync(string userName,
40                                                                                                                      string password,
41                                                                                                                      bool isPersistent,
42                                                                                                                      bool shouldLockout)
43         {
44             /*这里可以直接通过PasswordSignInAsync来校验,也可以重写~ */
45             //这里用Find方法会返回空的user。。。搞不懂。。
46             var user = base.UserManager.FindByName<BASE_USER, Guid>(userName);
47             if (user == null || user.Id == Guid.Empty)
48                 return Task.FromResult<SignInStatus>(SignInStatus.Failure);
49             else if (user.PWD != password)
50                 return Task.FromResult<SignInStatus>(SignInStatus.Failure);
51             else
52             {
53                 /*这个时候如果不写入到cooks里,在Home控制器的Index action里会被系统的
54                     Authorize刷选器拦截*/
55                 // 利用ASP.NET Identity获取identity 对象
56                 var identity = base.UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
57                 // 将上面拿到的identity对象登录
58                 base.AuthenticationManager.SignIn(new AuthenticationProperties()
59                 { IsPersistent = true }, identity.Result);
60                 return Task.FromResult<SignInStatus>(SignInStatus.Success);
61             }
62             /*这里如果你想直接使用微软的登入方法也可以,直接base.就ok啦*/
63             //return base.PasswordSignInAsync(userName,
64             //                                password,
65             //                                isPersistent,
66             //                                shouldLockout);
67         }
68 
69 
70     }
71 }

View Code

View Code

 

 

地方最根本的格局就是PasswordSignInAsync,这些措施正是登6方法。

上边最重要的点子便是PasswordSignInAsync,这一个法子正是登入方法。

 

 

能够说我们封装的工作已经实现了,封装了四个类

能够说咱俩封装的劳作已经形成了,封装了五个类

bf88必发唯一官网 66

bf88必发唯一官网 67

 

 

 今后大家看Controller里的代码是怎么写的吗~

 未来我们看Controller里的代码是怎么写的啊~

那是注册的Action,所属Controller当然是AccountController啦。。

那是登记的Action,所属Controller当然是AccountController啦。。

bf88必发唯一官网 68bf88必发唯一官网 69

bf88必发唯一官网 70bf88必发唯一官网 71

 1  /// <summary>
 2         /// 注册
 3         /// </summary>
 4         /// <returns></returns>
 5         [HttpPost]
 6         [AllowAnonymous]
 7         public async Task<ActionResult> Register(BASE_USER user)
 8         { 
 9             Microsoft.Owin.IOwinContext OwinContext = HttpContext.GetOwinContext();
10             //用户储存
11             HsUserStore userStore = new HsUserStore();
12             //UserManager
13             HsUserManager UserManager = new HsUserManager(userStore);
14             IdentityResult result = await UserManager.CreateAsync(user);
15             if (result.Succeeded)
16             {
17                 Response.Write("注册成功!");
18                 return RedirectToAction("index", "home");
19             }
20             return View();
21         }
22 
23         [AllowAnonymous]
24         public ActionResult Register()
25         {
26             return View();
27         }
 1  /// <summary>
 2         /// 注册
 3         /// </summary>
 4         /// <returns></returns>
 5         [HttpPost]
 6         [AllowAnonymous]
 7         public async Task<ActionResult> Register(BASE_USER user)
 8         { 
 9             Microsoft.Owin.IOwinContext OwinContext = HttpContext.GetOwinContext();
10             //用户储存
11             HsUserStore userStore = new HsUserStore();
12             //UserManager
13             HsUserManager UserManager = new HsUserManager(userStore);
14             IdentityResult result = await UserManager.CreateAsync(user);
15             if (result.Succeeded)
16             {
17                 Response.Write("注册成功!");
18                 return RedirectToAction("index", "home");
19             }
20             return View();
21         }
22 
23         [AllowAnonymous]
24         public ActionResult Register()
25         {
26             return View();
27         }

View Code

View Code

 

 

接下去是登入的Action代码~

接下去是登陆的Action代码~

bf88必发唯一官网 72bf88必发唯一官网 73

bf88必发唯一官网 74bf88必发唯一官网 75

 1         [AllowAnonymous]
 2         public ActionResult Login()
 3         {
 4             return View();
 5         }
 6 
 7 
 8         [HttpPost]
 9         [AllowAnonymous]
10         public async Task<ActionResult> Login(BASE_USER user)
11         {
12             if (string.IsNullOrEmpty(user.UserName)) { return View(); }
13             if (string.IsNullOrEmpty(user.PWD)) { return View(); }
14             //Context
15             Microsoft.Owin.IOwinContext OwinContext = HttpContext.GetOwinContext();
16             //实例化UserStore对象
17             HsUserStore userStore = new HsUserStore();
18             //UserManager
19             HsUserManager userManager = new HsUserManager(userStore);
20             //授权对象
21             IAuthenticationManager autherticationManager = OwinContext.Authentication;
22             //登录管理对象
23             HsSignInManager signManager = new HsSignInManager(userManager, autherticationManager);
24 
25             //登录
26             Microsoft.AspNet.Identity.Owin.SignInStatus SignInStatus = Microsoft.AspNet.Identity.Owin.SignInStatus.Failure;
27             try
28             {
29                 SignInStatus = await signManager.PasswordSignInAsync(user.UserName,
30                                                                      user.PWD,
31                                                                      true,
32                                                                      shouldLockout: false);
33              
34             }catch(Exception ea)
35             {
36                  
37             }
38             //登录状态
39             switch (SignInStatus)
40             {
41                 //成功 同一个Control里跳转直接使用RecirectToAction(ActionName) 
42                 case Microsoft.AspNet.Identity.Owin.SignInStatus.Success:                
43                     //不同控制器使用RedirectToAction
44                     return RedirectToAction("Index", "Home"); //可以直接跳到别的Controller.                
45                 //锁定
46                 case Microsoft.AspNet.Identity.Owin.SignInStatus.LockedOut:
47                     Response.Write("账户被锁定啦~~~!");
48                     break;
49                 //失败
50                 case Microsoft.AspNet.Identity.Owin.SignInStatus.Failure:
51                     Response.Write("登录失败啦~~~!");
52                     break;
53                 //要求验证
54                 case Microsoft.AspNet.Identity.Owin.SignInStatus.RequiresVerification:
55                     Response.Write("需要验证!");
56                     break;
57 
58             }
59             return View();
60         }
 1         [AllowAnonymous]
 2         public ActionResult Login()
 3         {
 4             return View();
 5         }
 6 
 7 
 8         [HttpPost]
 9         [AllowAnonymous]
10         public async Task<ActionResult> Login(BASE_USER user)
11         {
12             if (string.IsNullOrEmpty(user.UserName)) { return View(); }
13             if (string.IsNullOrEmpty(user.PWD)) { return View(); }
14             //Context
15             Microsoft.Owin.IOwinContext OwinContext = HttpContext.GetOwinContext();
16             //实例化UserStore对象
17             HsUserStore userStore = new HsUserStore();
18             //UserManager
19             HsUserManager userManager = new HsUserManager(userStore);
20             //授权对象
21             IAuthenticationManager autherticationManager = OwinContext.Authentication;
22             //登录管理对象
23             HsSignInManager signManager = new HsSignInManager(userManager, autherticationManager);
24 
25             //登录
26             Microsoft.AspNet.Identity.Owin.SignInStatus SignInStatus = Microsoft.AspNet.Identity.Owin.SignInStatus.Failure;
27             try
28             {
29                 SignInStatus = await signManager.PasswordSignInAsync(user.UserName,
30                                                                      user.PWD,
31                                                                      true,
32                                                                      shouldLockout: false);
33              
34             }catch(Exception ea)
35             {
36                  
37             }
38             //登录状态
39             switch (SignInStatus)
40             {
41                 //成功 同一个Control里跳转直接使用RecirectToAction(ActionName) 
42                 case Microsoft.AspNet.Identity.Owin.SignInStatus.Success:                
43                     //不同控制器使用RedirectToAction
44                     return RedirectToAction("Index", "Home"); //可以直接跳到别的Controller.                
45                 //锁定
46                 case Microsoft.AspNet.Identity.Owin.SignInStatus.LockedOut:
47                     Response.Write("账户被锁定啦~~~!");
48                     break;
49                 //失败
50                 case Microsoft.AspNet.Identity.Owin.SignInStatus.Failure:
51                     Response.Write("登录失败啦~~~!");
52                     break;
53                 //要求验证
54                 case Microsoft.AspNet.Identity.Owin.SignInStatus.RequiresVerification:
55                     Response.Write("需要验证!");
56                     break;
57 
58             }
59             return View();
60         }

View Code

View Code

 

 

 

 

咱俩看大家Mvc路由暗中同意配置伊始页面是Home调整器下的Index

作者们看大家Mvc路由私下认可配置开头页面是Home调节器下的Index

bf88必发唯一官网 76

bf88必发唯一官网 77

 

 

 那是Home调节器下的Index证明

 那是Home调控器下的Index申明

bf88必发唯一官网 78

bf88必发唯一官网 79

 

 

 F五运作试下

 F5周转试下

 运行发掘浏览器直接跳转到了登6页面。。

 运营开采浏览器直接跳转到了登6页面。。

bf88必发唯一官网 80

bf88必发唯一官网 81

 

 

 

 

 

 

 在大家输入账号密码后,跳转到了Index页面

 在我们输入账号密码后,跳转到了Index页面

 

 

bf88必发唯一官网 82

bf88必发唯一官网 83

 

 

下一场大家用浏览器查看下cookie有怎么着变动~

下一场大家用浏览器查看下cookie有何样变动~

bf88必发唯一官网 84

bf88必发唯一官网 85

 

bf88必发唯一官网, 

发觉全体专门的事业成功后浏览器保存了名叫_Identity德姆o的
三个囤积项,整个正是在我们登录方法里奉行的。

察觉整整专门的学问成功后浏览器保存了名字为_Identity德姆o的
3个存款和储蓄项,整个正是在大家登入方法里实践的。

 

 

好啊,整个Identity认证不信赖EF已经达成了,多少个大旨点正是亟需贯彻IUser接口以及各个Store。。然后将得以落成各样Store的类注入到UserManager构造函数里

好啊,整个Identity认证不正视EF已经得以完成了,多少个宗旨点正是内需达成IUser接口以及各类Store。。然后将达成各个Store的类注入到UserManager构造函数里

等有时光再得以达成下Identity命名空间下的角色管理那一块吧。。。不得不说微软的接口真是封装的好哎~

等有时间再得以落成下Identity命名空间下的剧中人物管理那1块呢。。。不得不说微软的接口真是封装的好哎~

此处谢谢下开源中夏族民共和国的李朝强,小编是看她博客再本身施行出来的~谢谢谢谢~

这里多谢下开源中华夏族民共和国的李朝强,作者是看她博客再本人实行出来的~多谢感激~

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图