From a3955f9ae28716037af77de2ec1180635320348a Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 13 Jul 2020 13:46:17 +0800 Subject: [PATCH 01/32] Introduce AbpFileExtensionContentTypeProvider. --- ...lFileSystemApplicationBuilderExtensions.cs | 20 +- .../AbpAspNetCoreContentOptions.cs | 402 +++++++++++++++++- .../AbpFileExtensionContentTypeProvider.cs | 39 ++ 3 files changed, 440 insertions(+), 21 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpFileExtensionContentTypeProvider.cs diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs index 0557c37380..da9f65059f 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs @@ -1,18 +1,22 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.VirtualFileSystem; namespace Microsoft.AspNetCore.Builder { public static class VirtualFileSystemApplicationBuilderExtensions { - public static IApplicationBuilder UseVirtualFiles(this IApplicationBuilder app) + public static IApplicationBuilder UseVirtualFiles(this IApplicationBuilder app, Action configure = null) { - return app.UseStaticFiles( - new StaticFileOptions - { - FileProvider = app.ApplicationServices.GetRequiredService() - } - ); + var staticFileOptions = new StaticFileOptions + { + FileProvider = app.ApplicationServices.GetRequiredService(), + ContentTypeProvider = app.ApplicationServices.GetRequiredService() + }; + + configure?.Invoke(staticFileOptions); + + return app.UseStaticFiles(staticFileOptions); } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpAspNetCoreContentOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpAspNetCoreContentOptions.cs index ce6e454f54..f4b7d631cc 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpAspNetCoreContentOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpAspNetCoreContentOptions.cs @@ -1,14 +1,401 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; namespace Volo.Abp.AspNetCore.VirtualFileSystem { public class AbpAspNetCoreContentOptions { + public Dictionary ContentTypeMaps { get; } + public List AllowedExtraWebContentFolders { get; } + public List AllowedExtraWebContentFileExtensions { get; } public AbpAspNetCoreContentOptions() { + ContentTypeMaps = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + {".323", "text/h323"}, + {".3g2", "video/3gpp2"}, + {".3gp2", "video/3gpp2"}, + {".3gp", "video/3gpp"}, + {".3gpp", "video/3gpp"}, + {".aac", "audio/aac"}, + {".aaf", "application/octet-stream"}, + {".aca", "application/octet-stream"}, + {".accdb", "application/msaccess"}, + {".accde", "application/msaccess"}, + {".accdt", "application/msaccess"}, + {".acx", "application/internet-property-stream"}, + {".adt", "audio/vnd.dlna.adts"}, + {".adts", "audio/vnd.dlna.adts"}, + {".afm", "application/octet-stream"}, + {".ai", "application/postscript"}, + {".aif", "audio/x-aiff"}, + {".aifc", "audio/aiff"}, + {".aiff", "audio/aiff"}, + {".appcache", "text/cache-manifest"}, + {".application", "application/x-ms-application"}, + {".art", "image/x-jg"}, + {".asd", "application/octet-stream"}, + {".asf", "video/x-ms-asf"}, + {".asi", "application/octet-stream"}, + {".asm", "text/plain"}, + {".asr", "video/x-ms-asf"}, + {".asx", "video/x-ms-asf"}, + {".atom", "application/atom+xml"}, + {".au", "audio/basic"}, + {".avi", "video/x-msvideo"}, + {".axs", "application/olescript"}, + {".bas", "text/plain"}, + {".bcpio", "application/x-bcpio"}, + {".bin", "application/octet-stream"}, + {".bmp", "image/bmp"}, + {".c", "text/plain"}, + {".cab", "application/vnd.ms-cab-compressed"}, + {".calx", "application/vnd.ms-office.calx"}, + {".cat", "application/vnd.ms-pki.seccat"}, + {".cdf", "application/x-cdf"}, + {".chm", "application/octet-stream"}, + {".class", "application/x-java-applet"}, + {".clp", "application/x-msclip"}, + {".cmx", "image/x-cmx"}, + {".cnf", "text/plain"}, + {".cod", "image/cis-cod"}, + {".cpio", "application/x-cpio"}, + {".cpp", "text/plain"}, + {".crd", "application/x-mscardfile"}, + {".crl", "application/pkix-crl"}, + {".crt", "application/x-x509-ca-cert"}, + {".csh", "application/x-csh"}, + {".css", "text/css"}, + {".csv", "application/octet-stream"}, + {".cur", "application/octet-stream"}, + {".dcr", "application/x-director"}, + {".deploy", "application/octet-stream"}, + {".der", "application/x-x509-ca-cert"}, + {".dib", "image/bmp"}, + {".dir", "application/x-director"}, + {".disco", "text/xml"}, + {".dlm", "text/dlm"}, + {".doc", "application/msword"}, + {".docm", "application/vnd.ms-word.document.macroEnabled.12"}, + {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, + {".dot", "application/msword"}, + {".dotm", "application/vnd.ms-word.template.macroEnabled.12"}, + {".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"}, + {".dsp", "application/octet-stream"}, + {".dtd", "text/xml"}, + {".dvi", "application/x-dvi"}, + {".dvr-ms", "video/x-ms-dvr"}, + {".dwf", "drawing/x-dwf"}, + {".dwp", "application/octet-stream"}, + {".dxr", "application/x-director"}, + {".eml", "message/rfc822"}, + {".emz", "application/octet-stream"}, + {".eot", "application/vnd.ms-fontobject"}, + {".eps", "application/postscript"}, + {".etx", "text/x-setext"}, + {".evy", "application/envoy"}, + {".fdf", "application/vnd.fdf"}, + {".fif", "application/fractals"}, + {".fla", "application/octet-stream"}, + {".flr", "x-world/x-vrml"}, + {".flv", "video/x-flv"}, + {".gif", "image/gif"}, + {".gtar", "application/x-gtar"}, + {".gz", "application/x-gzip"}, + {".h", "text/plain"}, + {".hdf", "application/x-hdf"}, + {".hdml", "text/x-hdml"}, + {".hhc", "application/x-oleobject"}, + {".hhk", "application/octet-stream"}, + {".hhp", "application/octet-stream"}, + {".hlp", "application/winhlp"}, + {".hqx", "application/mac-binhex40"}, + {".hta", "application/hta"}, + {".htc", "text/x-component"}, + {".htm", "text/html"}, + {".html", "text/html"}, + {".htt", "text/webviewhtml"}, + {".hxt", "text/html"}, + {".ical", "text/calendar"}, + {".icalendar", "text/calendar"}, + {".ico", "image/x-icon"}, + {".ics", "text/calendar"}, + {".ief", "image/ief"}, + {".ifb", "text/calendar"}, + {".iii", "application/x-iphone"}, + {".inf", "application/octet-stream"}, + {".ins", "application/x-internet-signup"}, + {".isp", "application/x-internet-signup"}, + {".IVF", "video/x-ivf"}, + {".jar", "application/java-archive"}, + {".java", "application/octet-stream"}, + {".jck", "application/liquidmotion"}, + {".jcz", "application/liquidmotion"}, + {".jfif", "image/pjpeg"}, + {".jpb", "application/octet-stream"}, + {".jpe", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".jpg", "image/jpeg"}, + {".js", "application/javascript"}, + {".json", "application/json"}, + {".jsx", "text/jscript"}, + {".latex", "application/x-latex"}, + {".lit", "application/x-ms-reader"}, + {".lpk", "application/octet-stream"}, + {".lsf", "video/x-la-asf"}, + {".lsx", "video/x-la-asf"}, + {".lzh", "application/octet-stream"}, + {".m13", "application/x-msmediaview"}, + {".m14", "application/x-msmediaview"}, + {".m1v", "video/mpeg"}, + {".m2ts", "video/vnd.dlna.mpeg-tts"}, + {".m3u", "audio/x-mpegurl"}, + {".m4a", "audio/mp4"}, + {".m4v", "video/mp4"}, + {".man", "application/x-troff-man"}, + {".manifest", "application/x-ms-manifest"}, + {".map", "text/plain"}, + {".markdown", "text/markdown"}, + {".md", "text/markdown"}, + {".mdb", "application/x-msaccess"}, + {".mdp", "application/octet-stream"}, + {".me", "application/x-troff-me"}, + {".mht", "message/rfc822"}, + {".mhtml", "message/rfc822"}, + {".mid", "audio/mid"}, + {".midi", "audio/mid"}, + {".mix", "application/octet-stream"}, + {".mmf", "application/x-smaf"}, + {".mno", "text/xml"}, + {".mny", "application/x-msmoney"}, + {".mov", "video/quicktime"}, + {".movie", "video/x-sgi-movie"}, + {".mp2", "video/mpeg"}, + {".mp3", "audio/mpeg"}, + {".mp4", "video/mp4"}, + {".mp4v", "video/mp4"}, + {".mpa", "video/mpeg"}, + {".mpe", "video/mpeg"}, + {".mpeg", "video/mpeg"}, + {".mpg", "video/mpeg"}, + {".mpp", "application/vnd.ms-project"}, + {".mpv2", "video/mpeg"}, + {".ms", "application/x-troff-ms"}, + {".msi", "application/octet-stream"}, + {".mso", "application/octet-stream"}, + {".mvb", "application/x-msmediaview"}, + {".mvc", "application/x-miva-compiled"}, + {".nc", "application/x-netcdf"}, + {".nsc", "video/x-ms-asf"}, + {".nws", "message/rfc822"}, + {".ocx", "application/octet-stream"}, + {".oda", "application/oda"}, + {".odc", "text/x-ms-odc"}, + {".ods", "application/oleobject"}, + {".oga", "audio/ogg"}, + {".ogg", "video/ogg"}, + {".ogv", "video/ogg"}, + {".ogx", "application/ogg"}, + {".one", "application/onenote"}, + {".onea", "application/onenote"}, + {".onetoc", "application/onenote"}, + {".onetoc2", "application/onenote"}, + {".onetmp", "application/onenote"}, + {".onepkg", "application/onenote"}, + {".osdx", "application/opensearchdescription+xml"}, + {".otf", "font/otf"}, + {".p10", "application/pkcs10"}, + {".p12", "application/x-pkcs12"}, + {".p7b", "application/x-pkcs7-certificates"}, + {".p7c", "application/pkcs7-mime"}, + {".p7m", "application/pkcs7-mime"}, + {".p7r", "application/x-pkcs7-certreqresp"}, + {".p7s", "application/pkcs7-signature"}, + {".pbm", "image/x-portable-bitmap"}, + {".pcx", "application/octet-stream"}, + {".pcz", "application/octet-stream"}, + {".pdf", "application/pdf"}, + {".pfb", "application/octet-stream"}, + {".pfm", "application/octet-stream"}, + {".pfx", "application/x-pkcs12"}, + {".pgm", "image/x-portable-graymap"}, + {".pko", "application/vnd.ms-pki.pko"}, + {".pma", "application/x-perfmon"}, + {".pmc", "application/x-perfmon"}, + {".pml", "application/x-perfmon"}, + {".pmr", "application/x-perfmon"}, + {".pmw", "application/x-perfmon"}, + {".png", "image/png"}, + {".pnm", "image/x-portable-anymap"}, + {".pnz", "image/png"}, + {".pot", "application/vnd.ms-powerpoint"}, + {".potm", "application/vnd.ms-powerpoint.template.macroEnabled.12"}, + {".potx", "application/vnd.openxmlformats-officedocument.presentationml.template"}, + {".ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12"}, + {".ppm", "image/x-portable-pixmap"}, + {".pps", "application/vnd.ms-powerpoint"}, + {".ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12"}, + {".ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow"}, + {".ppt", "application/vnd.ms-powerpoint"}, + {".pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12"}, + {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, + {".prf", "application/pics-rules"}, + {".prm", "application/octet-stream"}, + {".prx", "application/octet-stream"}, + {".ps", "application/postscript"}, + {".psd", "application/octet-stream"}, + {".psm", "application/octet-stream"}, + {".psp", "application/octet-stream"}, + {".pub", "application/x-mspublisher"}, + {".qt", "video/quicktime"}, + {".qtl", "application/x-quicktimeplayer"}, + {".qxd", "application/octet-stream"}, + {".ra", "audio/x-pn-realaudio"}, + {".ram", "audio/x-pn-realaudio"}, + {".rar", "application/octet-stream"}, + {".ras", "image/x-cmu-raster"}, + {".rf", "image/vnd.rn-realflash"}, + {".rgb", "image/x-rgb"}, + {".rm", "application/vnd.rn-realmedia"}, + {".rmi", "audio/mid"}, + {".roff", "application/x-troff"}, + {".rpm", "audio/x-pn-realaudio-plugin"}, + {".rtf", "application/rtf"}, + {".rtx", "text/richtext"}, + {".scd", "application/x-msschedule"}, + {".sct", "text/scriptlet"}, + {".sea", "application/octet-stream"}, + {".setpay", "application/set-payment-initiation"}, + {".setreg", "application/set-registration-initiation"}, + {".sgml", "text/sgml"}, + {".sh", "application/x-sh"}, + {".shar", "application/x-shar"}, + {".sit", "application/x-stuffit"}, + {".sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12"}, + {".sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide"}, + {".smd", "audio/x-smd"}, + {".smi", "application/octet-stream"}, + {".smx", "audio/x-smd"}, + {".smz", "audio/x-smd"}, + {".snd", "audio/basic"}, + {".snp", "application/octet-stream"}, + {".spc", "application/x-pkcs7-certificates"}, + {".spl", "application/futuresplash"}, + {".spx", "audio/ogg"}, + {".src", "application/x-wais-source"}, + {".ssm", "application/streamingmedia"}, + {".sst", "application/vnd.ms-pki.certstore"}, + {".stl", "application/vnd.ms-pki.stl"}, + {".sv4cpio", "application/x-sv4cpio"}, + {".sv4crc", "application/x-sv4crc"}, + {".svg", "image/svg+xml"}, + {".svgz", "image/svg+xml"}, + {".swf", "application/x-shockwave-flash"}, + {".t", "application/x-troff"}, + {".tar", "application/x-tar"}, + {".tcl", "application/x-tcl"}, + {".tex", "application/x-tex"}, + {".texi", "application/x-texinfo"}, + {".texinfo", "application/x-texinfo"}, + {".tgz", "application/x-compressed"}, + {".thmx", "application/vnd.ms-officetheme"}, + {".thn", "application/octet-stream"}, + {".tif", "image/tiff"}, + {".tiff", "image/tiff"}, + {".toc", "application/octet-stream"}, + {".tr", "application/x-troff"}, + {".trm", "application/x-msterminal"}, + {".ts", "video/vnd.dlna.mpeg-tts"}, + {".tsv", "text/tab-separated-values"}, + {".ttc", "application/x-font-ttf"}, + {".ttf", "application/x-font-ttf"}, + {".tts", "video/vnd.dlna.mpeg-tts"}, + {".txt", "text/plain"}, + {".u32", "application/octet-stream"}, + {".uls", "text/iuls"}, + {".ustar", "application/x-ustar"}, + {".vbs", "text/vbscript"}, + {".vcf", "text/x-vcard"}, + {".vcs", "text/plain"}, + {".vdx", "application/vnd.ms-visio.viewer"}, + {".vml", "text/xml"}, + {".vsd", "application/vnd.visio"}, + {".vss", "application/vnd.visio"}, + {".vst", "application/vnd.visio"}, + {".vsto", "application/x-ms-vsto"}, + {".vsw", "application/vnd.visio"}, + {".vsx", "application/vnd.visio"}, + {".vtx", "application/vnd.visio"}, + {".wasm", "application/wasm"}, + {".wav", "audio/wav"}, + {".wax", "audio/x-ms-wax"}, + {".wbmp", "image/vnd.wap.wbmp"}, + {".wcm", "application/vnd.ms-works"}, + {".wdb", "application/vnd.ms-works"}, + {".webm", "video/webm"}, + {".webp", "image/webp"}, + {".wks", "application/vnd.ms-works"}, + {".wm", "video/x-ms-wm"}, + {".wma", "audio/x-ms-wma"}, + {".wmd", "application/x-ms-wmd"}, + {".wmf", "application/x-msmetafile"}, + {".wml", "text/vnd.wap.wml"}, + {".wmlc", "application/vnd.wap.wmlc"}, + {".wmls", "text/vnd.wap.wmlscript"}, + {".wmlsc", "application/vnd.wap.wmlscriptc"}, + {".wmp", "video/x-ms-wmp"}, + {".wmv", "video/x-ms-wmv"}, + {".wmx", "video/x-ms-wmx"}, + {".wmz", "application/x-ms-wmz"}, + {".woff", "application/font-woff"}, // https://www.w3.org/TR/WOFF/#appendix-b + {".woff2", "font/woff2"}, // https://www.w3.org/TR/WOFF2/#IMT + {".wps", "application/vnd.ms-works"}, + {".wri", "application/x-mswrite"}, + {".wrl", "x-world/x-vrml"}, + {".wrz", "x-world/x-vrml"}, + {".wsdl", "text/xml"}, + {".wtv", "video/x-ms-wtv"}, + {".wvx", "video/x-ms-wvx"}, + {".x", "application/directx"}, + {".xaf", "x-world/x-vrml"}, + {".xaml", "application/xaml+xml"}, + {".xap", "application/x-silverlight-app"}, + {".xbap", "application/x-ms-xbap"}, + {".xbm", "image/x-xbitmap"}, + {".xdr", "text/plain"}, + {".xht", "application/xhtml+xml"}, + {".xhtml", "application/xhtml+xml"}, + {".xla", "application/vnd.ms-excel"}, + {".xlam", "application/vnd.ms-excel.addin.macroEnabled.12"}, + {".xlc", "application/vnd.ms-excel"}, + {".xlm", "application/vnd.ms-excel"}, + {".xls", "application/vnd.ms-excel"}, + {".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12"}, + {".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12"}, + {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, + {".xlt", "application/vnd.ms-excel"}, + {".xltm", "application/vnd.ms-excel.template.macroEnabled.12"}, + {".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template"}, + {".xlw", "application/vnd.ms-excel"}, + {".xml", "text/xml"}, + {".xof", "x-world/x-vrml"}, + {".xpm", "image/x-xpixmap"}, + {".xps", "application/vnd.ms-xpsdocument"}, + {".xsd", "text/xml"}, + {".xsf", "text/xml"}, + {".xsl", "text/xml"}, + {".xslt", "text/xml"}, + {".xsn", "application/octet-stream"}, + {".xtp", "application/octet-stream"}, + {".xwd", "image/x-xwindowdump"}, + {".z", "application/x-compress"}, + {".zip", "application/x-zip-compressed"}, + }; + AllowedExtraWebContentFolders = new List { "/Pages", @@ -16,18 +403,7 @@ namespace Volo.Abp.AspNetCore.VirtualFileSystem "/Themes" }; - AllowedExtraWebContentFileExtensions = new List - { - ".js", - ".css", - ".png", - ".jpg", - ".jpeg", - ".woff", - ".woff2", - ".tff", - ".otf" - }; + AllowedExtraWebContentFileExtensions = ContentTypeMaps.Select(x => x.Key).ToList(); } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpFileExtensionContentTypeProvider.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpFileExtensionContentTypeProvider.cs new file mode 100644 index 0000000000..82ca1c5539 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/VirtualFileSystem/AbpFileExtensionContentTypeProvider.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.VirtualFileSystem +{ + public class AbpFileExtensionContentTypeProvider : IContentTypeProvider, ITransientDependency + { + protected AbpAspNetCoreContentOptions Options { get; } + + public AbpFileExtensionContentTypeProvider(IOptions abpAspNetCoreContentOptions) + { + Options = abpAspNetCoreContentOptions.Value; + } + + public bool TryGetContentType(string subpath, out string contentType) + { + var extension = GetExtension(subpath); + if (extension == null) + { + contentType = null; + return false; + } + + return Options.ContentTypeMaps.TryGetValue(extension, out contentType); + } + + protected virtual string GetExtension(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + return null; + } + + var index = path.LastIndexOf('.'); + return index < 0 ? null : path.Substring(index); + } + } +} From 9fcc3a123ada4d3f5f39a6dd1c9b6cd5656abc21 Mon Sep 17 00:00:00 2001 From: Richard Forrest Date: Wed, 15 Jul 2020 10:43:05 +0100 Subject: [PATCH 02/32] Add details on the correct use of unit of work in event handlers --- docs/en/Distributed-Event-Bus.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/en/Distributed-Event-Bus.md b/docs/en/Distributed-Event-Bus.md index 947b0f3142..0f2900e988 100644 --- a/docs/en/Distributed-Event-Bus.md +++ b/docs/en/Distributed-Event-Bus.md @@ -178,8 +178,11 @@ That's all. You can inject any service and perform any required logic here. A single event handler class can **subscribe to multiple events** but implementing the `IDistributedEventHandler` interface for each event type. +In your handler if you call a methods on a Repository you may find that you get an `ObjectDisposedException` being thrown. This will be because the unit of work being used by the Repository has been disposed in another context e.g. an ASP.net controller action. You will need to create a specific unit of work for your `HandleEventAsync` method. You can either use the `IUnitOfWorkManager.Begin` method or use the `UnitOfWorkAttribute` on the method. See the [Unit of work document](Unit-of-work.md) for more details. + > The handler class must be registered to the dependency injection (DI). The sample above uses the `ITransientDependency` to accomplish it. See the [DI document](Dependency-Injection.md) for more options. + ## Pre-Defined Events ABP Framework **automatically publishes** distributed events for **create, update and delete** operations for an [entity](Entities.md) once you configure it. From 5ef60faa8c1e24de09afea17667625e47b37b90f Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 20 Jul 2020 08:56:48 +0800 Subject: [PATCH 03/32] Introduce BasicAggregateRoot base class Resolve #4808 --- .../Volo/Abp/Domain/Entities/AggregateRoot.cs | 76 +-------------- .../Abp/Domain/Entities/BasicAggregateRoot.cs | 95 +++++++++++++++++++ 2 files changed, 98 insertions(+), 73 deletions(-) create mode 100644 framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/AggregateRoot.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/AggregateRoot.cs index b0c20131ef..09af979e93 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/AggregateRoot.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/AggregateRoot.cs @@ -9,9 +9,7 @@ using Volo.Abp.ObjectExtending; namespace Volo.Abp.Domain.Entities { [Serializable] - public abstract class AggregateRoot : Entity, - IAggregateRoot, - IGeneratesDomainEvents, + public abstract class AggregateRoot : BasicAggregateRoot, IHasExtraProperties, IHasConcurrencyStamp { @@ -20,9 +18,6 @@ namespace Volo.Abp.Domain.Entities [DisableAuditing] public virtual string ConcurrencyStamp { get; set; } - private readonly ICollection _localEvents = new Collection(); - private readonly ICollection _distributedEvents = new Collection(); - protected AggregateRoot() { ConcurrencyStamp = Guid.NewGuid().ToString("N"); @@ -30,36 +25,6 @@ namespace Volo.Abp.Domain.Entities this.SetDefaultsForExtraProperties(); } - protected virtual void AddLocalEvent(object eventData) - { - _localEvents.Add(eventData); - } - - protected virtual void AddDistributedEvent(object eventData) - { - _distributedEvents.Add(eventData); - } - - public virtual IEnumerable GetLocalEvents() - { - return _localEvents; - } - - public virtual IEnumerable GetDistributedEvents() - { - return _distributedEvents; - } - - public virtual void ClearLocalEvents() - { - _localEvents.Clear(); - } - - public virtual void ClearDistributedEvents() - { - _distributedEvents.Clear(); - } - public virtual IEnumerable Validate(ValidationContext validationContext) { return ExtensibleObjectValidator.GetValidationErrors( @@ -70,9 +35,7 @@ namespace Volo.Abp.Domain.Entities } [Serializable] - public abstract class AggregateRoot : Entity, - IAggregateRoot, - IGeneratesDomainEvents, + public abstract class AggregateRoot : BasicAggregateRoot, IHasExtraProperties, IHasConcurrencyStamp { @@ -81,9 +44,6 @@ namespace Volo.Abp.Domain.Entities [DisableAuditing] public virtual string ConcurrencyStamp { get; set; } - private readonly ICollection _localEvents = new Collection(); - private readonly ICollection _distributedEvents = new Collection(); - protected AggregateRoot() { ConcurrencyStamp = Guid.NewGuid().ToString("N"); @@ -99,36 +59,6 @@ namespace Volo.Abp.Domain.Entities this.SetDefaultsForExtraProperties(); } - protected virtual void AddLocalEvent(object eventData) - { - _localEvents.Add(eventData); - } - - protected virtual void AddDistributedEvent(object eventData) - { - _distributedEvents.Add(eventData); - } - - public virtual IEnumerable GetLocalEvents() - { - return _localEvents; - } - - public virtual IEnumerable GetDistributedEvents() - { - return _distributedEvents; - } - - public virtual void ClearLocalEvents() - { - _localEvents.Clear(); - } - - public virtual void ClearDistributedEvents() - { - _distributedEvents.Clear(); - } - public virtual IEnumerable Validate(ValidationContext validationContext) { return ExtensibleObjectValidator.GetValidationErrors( @@ -137,4 +67,4 @@ namespace Volo.Abp.Domain.Entities ); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs new file mode 100644 index 0000000000..42b0ba1320 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace Volo.Abp.Domain.Entities +{ + [Serializable] + public abstract class BasicAggregateRoot : Entity, + IAggregateRoot, + IGeneratesDomainEvents + { + private readonly ICollection _distributedEvents = new Collection(); + private readonly ICollection _localEvents = new Collection(); + + public virtual IEnumerable GetLocalEvents() + { + return _localEvents; + } + + public virtual IEnumerable GetDistributedEvents() + { + return _distributedEvents; + } + + public virtual void ClearLocalEvents() + { + _localEvents.Clear(); + } + + public virtual void ClearDistributedEvents() + { + _distributedEvents.Clear(); + } + + protected virtual void AddLocalEvent(object eventData) + { + _localEvents.Add(eventData); + } + + protected virtual void AddDistributedEvent(object eventData) + { + _distributedEvents.Add(eventData); + } + } + + [Serializable] + public abstract class BasicAggregateRoot : Entity, + IAggregateRoot, + IGeneratesDomainEvents + { + private readonly ICollection _distributedEvents = new Collection(); + private readonly ICollection _localEvents = new Collection(); + + protected BasicAggregateRoot() + { + + } + + protected BasicAggregateRoot(TKey id) + : base(id) + { + + } + + public virtual IEnumerable GetLocalEvents() + { + return _localEvents; + } + + public virtual IEnumerable GetDistributedEvents() + { + return _distributedEvents; + } + + public virtual void ClearLocalEvents() + { + _localEvents.Clear(); + } + + public virtual void ClearDistributedEvents() + { + _distributedEvents.Clear(); + } + + protected virtual void AddLocalEvent(object eventData) + { + _localEvents.Add(eventData); + } + + protected virtual void AddDistributedEvent(object eventData) + { + _distributedEvents.Add(eventData); + } + } +} From 4658933fb6720ec8b46d988b1b8a894eed7618e1 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 24 Jul 2020 14:56:03 +0800 Subject: [PATCH 04/32] Delete related entities when deleting Identity Server Client. Fix #4870 --- .../Clients/ClientRepository.cs | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs index 5b350d0365..1c7a0ccccb 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/Clients/ClientRepository.cs @@ -53,6 +53,56 @@ namespace Volo.Abp.IdentityServer.Clients return await DbSet.AnyAsync(c => c.Id != expectedId && c.ClientId == clientId, cancellationToken: cancellationToken); } + public override async Task DeleteAsync(Guid id, bool autoSave = false, CancellationToken cancellationToken = default) + { + foreach (var clientGrantType in DbContext.Set().Where(x => x.ClientId == id)) + { + DbContext.Set().Remove(clientGrantType); + } + + foreach (var clientRedirectUri in DbContext.Set().Where(x => x.ClientId == id)) + { + DbContext.Set().Remove(clientRedirectUri); + } + + foreach (var clientPostLogoutRedirectUri in DbContext.Set().Where(x => x.ClientId == id)) + { + DbContext.Set().Remove(clientPostLogoutRedirectUri); + } + + foreach (var clientScope in DbContext.Set().Where(x => x.ClientId == id)) + { + DbContext.Set().Remove(clientScope); + } + + foreach (var clientSecret in DbContext.Set().Where(x => x.ClientId == id)) + { + DbContext.Set().Remove(clientSecret); + } + + foreach (var clientClaim in DbContext.Set().Where(x => x.ClientId == id)) + { + DbContext.Set().Remove(clientClaim); + } + + foreach (var clientIdPRestriction in DbContext.Set().Where(x => x.ClientId == id)) + { + DbContext.Set().Remove(clientIdPRestriction); + } + + foreach (var clientCorsOrigin in DbContext.Set().Where(x => x.ClientId == id)) + { + DbContext.Set().Remove(clientCorsOrigin); + } + + foreach (var clientProperty in DbContext.Set().Where(x => x.ClientId == id)) + { + DbContext.Set().Remove(clientProperty); + } + + await base.DeleteAsync(id, autoSave, cancellationToken); + } + public override IQueryable WithDetails() { return GetQueryable().IncludeDetails(); From cead9c1b8f0c866a33cd8161aecdfcfc5aabafb0 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 27 Jul 2020 08:43:45 +0800 Subject: [PATCH 05/32] Remove ITransientDependency interface from the DeviceFlowStore class. Resolve #4883 --- .../Abp/IdentityServer/Devices/DeviceFlowStore.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowStore.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowStore.cs index ba0ef757fe..25432e2d58 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowStore.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Devices/DeviceFlowStore.cs @@ -5,20 +5,19 @@ using IdentityServer4.Models; using IdentityServer4.Stores; using IdentityServer4.Stores.Serialization; using JetBrains.Annotations; -using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; namespace Volo.Abp.IdentityServer.Devices { - public class DeviceFlowStore : IDeviceFlowStore, ITransientDependency + public class DeviceFlowStore : IDeviceFlowStore { protected IDeviceFlowCodesRepository DeviceFlowCodesRepository { get; } protected IGuidGenerator GuidGenerator { get; } protected IPersistentGrantSerializer PersistentGrantSerializer { get; } public DeviceFlowStore( - IDeviceFlowCodesRepository deviceFlowCodesRepository, - IGuidGenerator guidGenerator, + IDeviceFlowCodesRepository deviceFlowCodesRepository, + IGuidGenerator guidGenerator, IPersistentGrantSerializer persistentGrantSerializer) { DeviceFlowCodesRepository = deviceFlowCodesRepository; @@ -46,7 +45,7 @@ namespace Volo.Abp.IdentityServer.Devices } ); } - + public virtual async Task FindByUserCodeAsync(string userCode) { Check.NotNull(userCode, nameof(userCode)); @@ -70,7 +69,7 @@ namespace Volo.Abp.IdentityServer.Devices var deviceCodes = await DeviceFlowCodesRepository .FindByDeviceCodeAsync(deviceCode) ; - + if (deviceCodes == null) { return null; From 8bb00671118d60424e8cac062c6ece9c98d10d49 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 27 Jul 2020 09:04:31 +0800 Subject: [PATCH 06/32] Added SaveChangesOnDbContextAsync method to the IEfCoreDbContext. Fix #4659 --- .../Volo/Abp/EntityFrameworkCore/AbpDbContext.cs | 8 ++++++++ .../Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index adfb530ce2..844a8da5f3 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -182,6 +182,14 @@ namespace Volo.Abp.EntityFrameworkCore } } + /// + /// This method will call the DbContext method directly of EF Core, which doesn't apply concepts of abp. + /// + public virtual Task SaveChangesOnDbContextAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default) + { + return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); + } + public virtual void Initialize(AbpEfCoreDbContextInitializationContext initializationContext) { if (initializationContext.UnitOfWork.Options.Timeout.HasValue && diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs index 761e15b6f2..931cbd6d04 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs @@ -24,6 +24,11 @@ namespace Volo.Abp.EntityFrameworkCore Task SaveChangesAsync(CancellationToken cancellationToken = default); + /// + /// This method will call the DbContext method directly of EF Core, which doesn't apply concepts of abp. + /// + Task SaveChangesOnDbContextAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default); + DbSet Set() where T: class; @@ -50,7 +55,7 @@ namespace Volo.Abp.EntityFrameworkCore void AttachRange([NotNull] IEnumerable entities); void AttachRange([NotNull] params object[] entities); - + EntityEntry Entry([NotNull] TEntity entity) where TEntity : class; EntityEntry Entry([NotNull] object entity); From 5e0bf84f5843e242dcf46472651d8402603d2273 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Tue, 28 Jul 2020 09:49:25 +0800 Subject: [PATCH 07/32] Use alerts to show the exception message in the register page. Fix #4896 --- .../Pages/Account/Register.cshtml.cs | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs index f6d626dd63..66e938d48d 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Register.cshtml.cs @@ -1,3 +1,4 @@ +using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; @@ -43,24 +44,30 @@ namespace Volo.Abp.Account.Web.Pages.Account { ValidateModel(); - await CheckSelfRegistrationAsync(); - - var registerDto = new RegisterDto + try { - AppName = "MVC", - EmailAddress = Input.EmailAddress, - Password = Input.Password, - UserName = Input.UserName - }; + await CheckSelfRegistrationAsync(); - var userDto = await AccountAppService.RegisterAsync(registerDto); - var user = await UserManager.GetByIdAsync(userDto.Id); + var registerDto = new RegisterDto + { + AppName = "MVC", + EmailAddress = Input.EmailAddress, + Password = Input.Password, + UserName = Input.UserName + }; - await UserManager.SetEmailAsync(user, Input.EmailAddress); + var userDto = await AccountAppService.RegisterAsync(registerDto); + var user = await UserManager.GetByIdAsync(userDto.Id); - await SignInManager.SignInAsync(user, isPersistent: false); + await SignInManager.SignInAsync(user, isPersistent: false); - return Redirect(ReturnUrl ?? "~/"); //TODO: How to ensure safety? IdentityServer requires it however it should be checked somehow! + return Redirect(ReturnUrl ?? "~/"); //TODO: How to ensure safety? IdentityServer requires it however it should be checked somehow! + } + catch (BusinessException e) + { + Alerts.Danger(e.Message); + return Page(); + } } protected virtual async Task CheckSelfRegistrationAsync() From 1c8d498e8bf907fbae8289e45770325be55faf13 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 30 Jul 2020 10:07:02 +0800 Subject: [PATCH 08/32] Upgrade Automapper to v10.0.0 Resolve #4918 --- framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj b/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj index 2fb39be54f..bd5cffe848 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj +++ b/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj @@ -21,7 +21,7 @@ - + From 53cd00a9c55ed9f54741e076ad7390e753955419 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 3 Aug 2020 09:43:57 +0800 Subject: [PATCH 09/32] Don't show UPDATED if it is already NEW Resolve #4941 --- .../Areas/Documents/TagHelpers/TreeTagHelper.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs b/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs index 5f7ae8e7a7..726121ab5d 100644 --- a/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs +++ b/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using System.Text; using Microsoft.AspNetCore.Razor.TagHelpers; @@ -132,8 +132,7 @@ namespace Volo.Docs.Areas.Documents.TagHelpers var newBadge = "" + _localizer["New"] + ""; badge += newBadge; } - - if (node.LastSignificantUpdateTime != null && node.LastSignificantUpdateTime + TimeSpan.FromDays(14) > DateTime.Now) + else if (node.LastSignificantUpdateTime != null && node.LastSignificantUpdateTime + TimeSpan.FromDays(14) > DateTime.Now) { var updBadge = "" + _localizer["Upd"] + ""; badge += updBadge; From 592b511614ffb319a65e9f415cf32d89bb401d7f Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Tue, 4 Aug 2020 10:42:13 +0800 Subject: [PATCH 10/32] Combine related log messages to ones. Resolve #4949 --- .../Mvc/ExceptionHandling/AbpExceptionFilter.cs | 12 ++++++++---- .../ExceptionHandling/AbpExceptionPageFilter.cs | 8 ++++++-- .../Extensions/Logging/AbpLoggerExtensions.cs | 9 ++++++--- .../Volo/Abp/Validation/AbpValidationException.cs | 14 +++++++++----- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs index 1ce177ba44..009d52b42f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionFilter.cs @@ -1,4 +1,5 @@ using System; +using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -25,7 +26,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling public AbpExceptionFilter( IExceptionToErrorInfoConverter errorInfoConverter, - IHttpExceptionStatusCodeFinder statusCodeFinder, + IHttpExceptionStatusCodeFinder statusCodeFinder, IJsonSerializer jsonSerializer) { _errorInfoConverter = errorInfoConverter; @@ -54,7 +55,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling { return true; } - + if (context.HttpContext.Request.CanAccept(MimeTypes.Application.Json)) { return true; @@ -81,8 +82,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling var logLevel = context.Exception.GetLogLevel(); - Logger.LogWithLevel(logLevel, $"---------- {nameof(RemoteServiceErrorInfo)} ----------"); - Logger.LogWithLevel(logLevel, _jsonSerializer.Serialize(remoteServiceErrorInfo, indented: true)); + var remoteServiceErrorInfoBuilder = new StringBuilder(); + remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); + remoteServiceErrorInfoBuilder.AppendLine( _jsonSerializer.Serialize(remoteServiceErrorInfo, indented: true)); + Logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString()); + Logger.LogException(context.Exception, logLevel); await context.HttpContext diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs index 9e449f0474..8e2356ff20 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ExceptionHandling/AbpExceptionPageFilter.cs @@ -1,4 +1,5 @@ using System; +using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -93,8 +94,11 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling var logLevel = context.Exception.GetLogLevel(); - Logger.LogWithLevel(logLevel, $"---------- {nameof(RemoteServiceErrorInfo)} ----------"); - Logger.LogWithLevel(logLevel, _jsonSerializer.Serialize(remoteServiceErrorInfo, indented: true)); + var remoteServiceErrorInfoBuilder = new StringBuilder(); + remoteServiceErrorInfoBuilder.AppendLine($"---------- {nameof(RemoteServiceErrorInfo)} ----------"); + remoteServiceErrorInfoBuilder.AppendLine( _jsonSerializer.Serialize(remoteServiceErrorInfo, indented: true)); + Logger.LogWithLevel(logLevel, remoteServiceErrorInfoBuilder.ToString()); + Logger.LogException(context.Exception, logLevel); await context.HttpContext diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Logging/AbpLoggerExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Logging/AbpLoggerExtensions.cs index a711271cd2..5d975b2e58 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Logging/AbpLoggerExtensions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Logging/AbpLoggerExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text; using Volo.Abp.ExceptionHandling; using Volo.Abp.Logging; @@ -87,12 +88,14 @@ namespace Microsoft.Extensions.Logging return; } - logger.LogWithLevel(logLevel, "---------- Exception Data ----------"); - + var exceptionData = new StringBuilder(); + exceptionData.AppendLine("---------- Exception Data ----------"); foreach (var key in exception.Data.Keys) { - logger.LogWithLevel(logLevel, $"{key} = {exception.Data[key]}"); + exceptionData.AppendLine($"{key} = {exception.Data[key]}"); } + + logger.LogWithLevel(logLevel, exceptionData.ToString()); } private static void LogSelfLogging(ILogger logger, Exception exception) diff --git a/framework/src/Volo.Abp.Validation.Abstractions/Volo/Abp/Validation/AbpValidationException.cs b/framework/src/Volo.Abp.Validation.Abstractions/Volo/Abp/Validation/AbpValidationException.cs index fb3be504c5..5781eaecca 100644 --- a/framework/src/Volo.Abp.Validation.Abstractions/Volo/Abp/Validation/AbpValidationException.cs +++ b/framework/src/Volo.Abp.Validation.Abstractions/Volo/Abp/Validation/AbpValidationException.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Runtime.Serialization; +using System.Text; using Microsoft.Extensions.Logging; using Volo.Abp.Logging; @@ -12,9 +13,9 @@ namespace Volo.Abp.Validation /// This exception type is used to throws validation exceptions. /// [Serializable] - public class AbpValidationException : AbpException, - IHasLogLevel, - IHasValidationErrors, + public class AbpValidationException : AbpException, + IHasLogLevel, + IHasValidationErrors, IExceptionWithSelfLogging { /// @@ -99,7 +100,8 @@ namespace Volo.Abp.Validation return; } - logger.LogWithLevel(LogLevel, "There are " + ValidationErrors.Count + " validation errors:"); + var validationErrors = new StringBuilder(); + validationErrors.AppendLine("There are " + ValidationErrors.Count + " validation errors:"); foreach (var validationResult in ValidationErrors) { var memberNames = ""; @@ -108,8 +110,10 @@ namespace Volo.Abp.Validation memberNames = " (" + string.Join(", ", validationResult.MemberNames) + ")"; } - logger.LogWithLevel(LogLevel, validationResult.ErrorMessage + memberNames); + validationErrors.AppendLine(validationResult.ErrorMessage + memberNames); } + + logger.LogWithLevel(LogLevel, validationErrors.ToString()); } } } From 736446f983c79c6904a584e7c06a4e59be474e32 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Thu, 6 Aug 2020 21:22:13 +0800 Subject: [PATCH 11/32] The AddQueryStringParameter method supports values of array type. Resolve #4969 --- .../Http/Client/DynamicProxying/UrlBuilder.cs | 16 ++++++++++++- .../PersonAppServiceClientProxy_Tests.cs | 24 ++++++++++++++++--- .../TestApp/Application/IPeopleAppService.cs | 5 +++- .../TestApp/Application/PeopleAppService.cs | 11 +++++++-- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs index 162da88f16..e4b82b21e1 100644 --- a/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs +++ b/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/UrlBuilder.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -100,7 +101,20 @@ namespace Volo.Abp.Http.Client.DynamicProxying { urlBuilder.Append(isFirstParam ? "?" : "&"); - urlBuilder.Append(name + "=" + System.Net.WebUtility.UrlEncode(ConvertValueToString(value))); + if (value.GetType().IsArray || (value.GetType().IsGenericType && value is IEnumerable)) + { + var index = 0; + foreach (var item in (IEnumerable) value) + { + urlBuilder.Append(name + $"[{index++}]=" + System.Net.WebUtility.UrlEncode(ConvertValueToString(item)) + "&"); + } + //remove & at the end of the urlBuilder. + urlBuilder.Remove(urlBuilder.Length - 1, 1); + } + else + { + urlBuilder.Append(name + "=" + System.Net.WebUtility.UrlEncode(ConvertValueToString(value))); + } } private static string ConvertValueToString([NotNull] object value) diff --git a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs index 5fa3d4ab66..e53e3cabbf 100644 --- a/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs +++ b/framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/PersonAppServiceClientProxy_Tests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -40,12 +41,29 @@ namespace Volo.Abp.Http.DynamicProxying [Fact] public async Task GetList() { - var people = await _peopleAppService.GetListAsync(new PagedAndSortedResultRequestDto()) - ; + var people = await _peopleAppService.GetListAsync(new PagedAndSortedResultRequestDto()); people.TotalCount.ShouldBeGreaterThan(0); people.Items.Count.ShouldBe((int) people.TotalCount); } + [Fact] + public async Task GetParams() + { + var id1 = Guid.NewGuid(); + var id2 = Guid.NewGuid(); + + var @params = await _peopleAppService.GetParams(new List + { + id1, + id2 + }, new[] {"name1", "name2"}); + + @params.ShouldContain(id1.ToString("N")); + @params.ShouldContain(id2.ToString("N")); + @params.ShouldContain("name1"); + @params.ShouldContain("name2"); + } + [Fact] public async Task Delete() { @@ -151,4 +169,4 @@ namespace Volo.Abp.Http.DynamicProxying result.Inner1.Inner2.Value3.ShouldBe("value three"); } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPeopleAppService.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPeopleAppService.cs index 38b0e87787..a34cd19ebb 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPeopleAppService.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPeopleAppService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; @@ -10,6 +11,8 @@ namespace Volo.Abp.TestApp.Application { Task> GetPhones(Guid id, GetPersonPhonesFilter filter); + Task> GetParams(IEnumerable ids, string[] names); + Task AddPhone(Guid id, PhoneDto phoneDto); Task RemovePhone(Guid id, string number); @@ -18,4 +21,4 @@ namespace Volo.Abp.TestApp.Application Task GetWithComplexType(GetWithComplexTypeInput input); } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs index 522f8d9794..cff72c7869 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleAppService.cs @@ -18,18 +18,25 @@ namespace Volo.Abp.TestApp.Application { } - + public async Task> GetPhones(Guid id, GetPersonPhonesFilter filter) { var phones = (await GetEntityByIdAsync(id)).Phones .WhereIf(filter.Type.HasValue, p => p.Type == filter.Type) .ToList(); - + return new ListResultDto( ObjectMapper.Map, List>(phones) ); } + public Task> GetParams(IEnumerable ids, string[] names) + { + var @params = ids.Select(id => id.ToString("N")).ToList(); + @params.AddRange(names); + return Task.FromResult(@params.ToList()); + } + public async Task AddPhone(Guid id, PhoneDto phoneDto) { var person = await GetEntityByIdAsync(id); From e311ebaf3d0a90186ae222ad4b482add2f29750e Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 7 Aug 2020 12:38:05 +0800 Subject: [PATCH 12/32] Refactor some code of Ldap. --- .../src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj | 2 +- .../Volo/Abp/Ldap/AbpLdapModule.cs | 6 +- .../Volo/Abp/Ldap/LdapManager.cs | 88 +++++++++---------- .../Volo.Abp.Ldap.Tests.csproj | 3 - .../Volo/Abp/Ldap/AbpLdapTestModule.cs | 51 +++++++++++ .../Volo/Abp/Ldap/Authenticate_Tests.cs | 7 +- .../Volo/Abp/Ldap/LdapManager_Tests.cs | 58 +----------- 7 files changed, 99 insertions(+), 116 deletions(-) create mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs diff --git a/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj index 229f3c6c7d..5339a68da1 100644 --- a/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj +++ b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj @@ -19,7 +19,7 @@ - + diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs index b35e1b1d59..216eee81b4 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs @@ -1,12 +1,8 @@ using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Autofac; using Volo.Abp.Modularity; namespace Volo.Abp.Ldap { - [DependsOn( - typeof(AbpAutofacModule) - )] public class AbpLdapModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) @@ -15,4 +11,4 @@ namespace Volo.Abp.Ldap Configure(configuration.GetSection("LDAP")); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs index 9e0b8f04a7..77d8d04d91 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs @@ -13,9 +13,8 @@ namespace Volo.Abp.Ldap { public class LdapManager : ILdapManager, ITransientDependency { - private readonly string _searchBase; - private readonly AbpLdapOptions _ldapOptions; - private readonly IHybridServiceScopeFactory _hybridServiceScopeFactory; + protected AbpLdapOptions LdapOptions { get; } + protected IHybridServiceScopeFactory HybridServiceScopeFactory { get; } private readonly string[] _attributes = { @@ -26,40 +25,39 @@ namespace Volo.Abp.Ldap public LdapManager(IOptions ldapSettingsOptions, IHybridServiceScopeFactory hybridServiceScopeFactory) { - _hybridServiceScopeFactory = hybridServiceScopeFactory; - _ldapOptions = ldapSettingsOptions.Value; - _searchBase = _ldapOptions.SearchBase; + HybridServiceScopeFactory = hybridServiceScopeFactory; + LdapOptions = ldapSettingsOptions.Value; } #region Organization /// /// query the specified organizations. - /// + /// /// filter: (&(name=xxx)(objectClass=organizationalUnit)) when name is not null /// filter: (&(objectClass=organizationalUnit)) when name is null - /// + /// /// /// /// - public IList GetOrganizations(string name = null) + public virtual IList GetOrganizations(string name = null) { var conditions = new Dictionary { {"name", name}, {"objectClass", "organizationalUnit"}, }; - return Query(_searchBase, conditions); + return Query(LdapOptions.SearchBase, conditions); } /// /// query the specified organization. - /// + /// /// filter: (&(distinguishedName=xxx)(objectClass=organizationalUnit)) when organizationName is not null - /// + /// /// /// /// - public LdapOrganization GetOrganization(string distinguishedName) + public virtual LdapOrganization GetOrganization(string distinguishedName) { distinguishedName = Check.NotNullOrWhiteSpace(distinguishedName, nameof(distinguishedName)); var conditions = new Dictionary @@ -67,17 +65,17 @@ namespace Volo.Abp.Ldap {"distinguishedName", distinguishedName}, {"objectClass", "organizationalUnit"}, }; - return QueryOne(_searchBase, conditions); + return QueryOne(LdapOptions.SearchBase, conditions); } - public void AddSubOrganization(string organizationName, LdapOrganization parentOrganization) + public virtual void AddSubOrganization(string organizationName, LdapOrganization parentOrganization) { organizationName = Check.NotNullOrWhiteSpace(organizationName, nameof(organizationName)); var dn = $"OU={organizationName},{parentOrganization.DistinguishedName}"; var attributeSet = new LdapAttributeSet { - new LdapAttribute("objectCategory", $"CN=Organizational-Unit,CN=Schema,CN=Configuration,{_ldapOptions.DomainDistinguishedName}"), + new LdapAttribute("objectCategory", $"CN=Organizational-Unit,CN=Schema,CN=Configuration,{LdapOptions.DomainDistinguishedName}"), new LdapAttribute("objectClass", new[] {"top", "organizationalUnit"}), new LdapAttribute("name", organizationName), }; @@ -90,7 +88,7 @@ namespace Volo.Abp.Ldap } } - public void AddSubOrganization(string organizationName, string parentDistinguishedName) + public virtual void AddSubOrganization(string organizationName, string parentDistinguishedName) { organizationName = Check.NotNullOrWhiteSpace(organizationName, nameof(organizationName)); parentDistinguishedName = @@ -110,7 +108,7 @@ namespace Volo.Abp.Ldap #region User /// /// query the specified users. - /// + /// /// filter: (&(name=xxx)(objectCategory=person)(objectClass=user)) when name is not null /// filter: (&(objectCategory=person)(objectClass=user)) when name is null /// @@ -119,13 +117,13 @@ namespace Volo.Abp.Ldap /// /// filter: (&(cn=xxx)(objectCategory=person)(objectClass=user)) when commonName is not null /// filter: (&(objectCategory=person)(objectClass=user)) when commonName is null - /// + /// /// /// /// /// /// - public IList GetUsers(string name = null, string displayName = null, string commonName = null) + public virtual IList GetUsers(string name = null, string displayName = null, string commonName = null) { var conditions = new Dictionary { @@ -135,18 +133,18 @@ namespace Volo.Abp.Ldap {"displayName", displayName}, {"cn", commonName}, }; - return Query(_searchBase, conditions); + return Query(LdapOptions.SearchBase, conditions); } /// /// query the specified User. - /// + /// /// filter: (&(distinguishedName=xxx)(objectCategory=person)(objectClass=user)) when distinguishedName is not null - /// + /// /// /// /// - public LdapUser GetUser(string distinguishedName) + public virtual LdapUser GetUser(string distinguishedName) { distinguishedName = Check.NotNullOrWhiteSpace(distinguishedName, nameof(distinguishedName)); var conditions = new Dictionary @@ -155,19 +153,19 @@ namespace Volo.Abp.Ldap {"objectClass", "user"}, {"distinguishedName", distinguishedName}, }; - return QueryOne(_searchBase, conditions); + return QueryOne(LdapOptions.SearchBase, conditions); } - public void AddUserToOrganization(string userName, string password, LdapOrganization parentOrganization) + public virtual void AddUserToOrganization(string userName, string password, LdapOrganization parentOrganization) { var dn = $"CN={userName},{parentOrganization.DistinguishedName}"; - var mail = $"{userName}@{_ldapOptions.DomainName}"; - sbyte[] encodedBytes = SupportClass.ToSByteArray(Encoding.Unicode.GetBytes($"\"{password}\"")); + var mail = $"{userName}@{LdapOptions.DomainName}"; + var encodedBytes = SupportClass.ToSByteArray(Encoding.Unicode.GetBytes($"\"{password}\"")); var attributeSet = new LdapAttributeSet { new LdapAttribute("instanceType", "4"), - new LdapAttribute("objectCategory", $"CN=Person,CN=Schema,CN=Configuration,{_ldapOptions.DomainDistinguishedName}"), + new LdapAttribute("objectCategory", $"CN=Person,CN=Schema,CN=Configuration,{LdapOptions.DomainDistinguishedName}"), new LdapAttribute("objectClass", new[] {"top", "person", "organizationalPerson", "user"}), new LdapAttribute("name", userName), new LdapAttribute("cn", userName), @@ -187,16 +185,16 @@ namespace Volo.Abp.Ldap } } - public void AddUserToOrganization(string userName, string password, string parentDistinguishedName) + public virtual void AddUserToOrganization(string userName, string password, string parentDistinguishedName) { var dn = $"CN={userName},{parentDistinguishedName}"; - var mail = $"{userName}@{_ldapOptions.DomainName}"; + var mail = $"{userName}@{LdapOptions.DomainName}"; sbyte[] encodedBytes = SupportClass.ToSByteArray(Encoding.Unicode.GetBytes($"\"{password}\"")); var attributeSet = new LdapAttributeSet { new LdapAttribute("instanceType", "4"), - new LdapAttribute("objectCategory", $"CN=Person,CN=Schema,CN=Configuration,{_ldapOptions.DomainDistinguishedName}"), + new LdapAttribute("objectCategory", $"CN=Person,CN=Schema,CN=Configuration,{LdapOptions.DomainDistinguishedName}"), new LdapAttribute("objectClass", new[] {"top", "person", "organizationalPerson", "user"}), new LdapAttribute("name", userName), new LdapAttribute("cn", userName), @@ -221,12 +219,12 @@ namespace Volo.Abp.Ldap #region Authenticate /// - /// Authenticate + /// Authenticate /// /// E.g administrator@yourdomain.com.cn /// /// - public bool Authenticate(string userDomainName, string password) + public virtual bool Authenticate(string userDomainName, string password) { try { @@ -237,7 +235,7 @@ namespace Volo.Abp.Ldap } catch (Exception ex) { - using (var scope = _hybridServiceScopeFactory.CreateScope()) + using (var scope = HybridServiceScopeFactory.CreateScope()) { scope.ServiceProvider .GetRequiredService() @@ -250,20 +248,20 @@ namespace Volo.Abp.Ldap #endregion - private ILdapConnection GetConnection(string bindUserName = null, string bindUserPassword = null) + protected virtual ILdapConnection GetConnection(string bindUserName = null, string bindUserPassword = null) { // bindUserName/bindUserPassword only be used when authenticate - bindUserName = bindUserName ?? _ldapOptions.Credentials.DomainUserName; - bindUserPassword = bindUserPassword ?? _ldapOptions.Credentials.Password; + bindUserName = bindUserName ?? LdapOptions.Credentials.DomainUserName; + bindUserPassword = bindUserPassword ?? LdapOptions.Credentials.Password; - var ldapConnection = new LdapConnection() { SecureSocketLayer = _ldapOptions.UseSsl }; - if (_ldapOptions.UseSsl) + var ldapConnection = new LdapConnection() { SecureSocketLayer = LdapOptions.UseSsl }; + if (LdapOptions.UseSsl) { ldapConnection.UserDefinedServerCertValidationDelegate += (sender, certificate, chain, sslPolicyErrors) => true; } - ldapConnection.Connect(_ldapOptions.ServerHost, _ldapOptions.ServerPort); + ldapConnection.Connect(LdapOptions.ServerHost, LdapOptions.ServerPort); - if (_ldapOptions.UseSsl) + if (LdapOptions.UseSsl) { ldapConnection.Bind(LdapConnection.Ldap_V3, bindUserName, bindUserPassword); } @@ -274,7 +272,7 @@ namespace Volo.Abp.Ldap return ldapConnection; } - private IList Query(string searchBase, Dictionary conditions) where T : class, ILdapEntry + protected virtual IList Query(string searchBase, Dictionary conditions) where T : class, ILdapEntry { var filter = LdapHelps.BuildFilter(conditions); @@ -307,7 +305,7 @@ namespace Volo.Abp.Ldap return result; } - private T QueryOne(string searchBase, Dictionary conditions) where T : class, ILdapEntry + protected virtual T QueryOne(string searchBase, Dictionary conditions) where T : class, ILdapEntry { var filter = LdapHelps.BuildFilter(conditions); @@ -340,4 +338,4 @@ namespace Volo.Abp.Ldap } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj b/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj index 3c1f9c96db..cea5e86688 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj @@ -9,9 +9,6 @@ - - - diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs new file mode 100644 index 0000000000..f3932e0a05 --- /dev/null +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs @@ -0,0 +1,51 @@ +using Volo.Abp.Modularity; + +namespace Volo.Abp.Ldap +{ + [DependsOn(typeof(AbpLdapModule))] + public class AbpLdapTestModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + // not use ssl + // "LDAP": { + // "ServerHost": "192.168.101.54", + // "ServerPort": 389, + // "UseSSL": false, + // "Credentials": { + // "DomainUserName": "administrator@yourdomain.com.cn", + // "Password": "yH.20190528" + // }, + // "SearchBase": "CN=Users,DC=yourdomain,DC=com,DC=cn", + // "DomainName": "yourdomain.com.cn", + // "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn" + // } + + // use ssl + // "LDAP": { + // "ServerHost": "192.168.101.54", + // "ServerPort": 636, + // "UseSSL": true, + // "Credentials": { + // "DomainUserName": "administrator@yourdomain.com.cn", + // "Password": "yH.20190528" + // }, + // "SearchBase": "CN=Users,DC=yourdomain,DC=com,DC=cn", + // "DomainName": "yourdomain.com.cn", + // "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn" + // } + + Configure(settings => + { + settings.ServerHost = "192.168.101.54"; + settings.ServerPort = 636; + settings.UseSsl = true; + settings.Credentials.DomainUserName = "administrator@yourdomain.com.cn"; + settings.Credentials.Password = "yH.20190528"; + settings.SearchBase = "DC=yourdomain,DC=com,DC=cn"; + settings.DomainName = "yourdomain.com.cn"; + settings.DomainDistinguishedName = "DC=yourdomain,DC=com,DC=cn"; + }); + } + } +} diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs index bf11262a99..46471893ce 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs @@ -6,13 +6,8 @@ using Xunit; namespace Volo.Abp.Ldap { - public class Authenticate_Tests : AbpIntegratedTest { - protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) - { - options.UseAutofac(); - } private readonly ILdapManager _ldapManager; private readonly LdapTestData _testData; @@ -68,4 +63,4 @@ namespace Volo.Abp.Ldap } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs index 3e83d26543..20382e5577 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs @@ -1,25 +1,17 @@ using System; using Shouldly; -using Volo.Abp.Modularity; using Volo.Abp.Testing; using Xunit; namespace Volo.Abp.Ldap { - - public class LdapManager_Tests : AbpIntegratedTest + public class LdapManager_Tests : AbpIntegratedTest { - protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) - { - options.UseAutofac(); - } - private readonly ILdapManager _ldapManager; private readonly LdapTestData _testData; public LdapManager_Tests() { - // ReSharper disable once VirtualMemberCallInConstructor _testData = GetRequiredService(); _ldapManager = GetRequiredService(); } @@ -195,52 +187,6 @@ namespace Volo.Abp.Ldap result.ShouldNotBeNull(); result.ShouldContain(e=>e.Name == randomName); } - - [DependsOn(typeof(AbpLdapModule))] - public class TestModule : AbpModule - { - public override void ConfigureServices(ServiceConfigurationContext context) - { - // not use ssl - // "LDAP": { - // "ServerHost": "192.168.101.54", - // "ServerPort": 389, - // "UseSSL": false, - // "Credentials": { - // "DomainUserName": "administrator@yourdomain.com.cn", - // "Password": "yH.20190528" - // }, - // "SearchBase": "CN=Users,DC=yourdomain,DC=com,DC=cn", - // "DomainName": "yourdomain.com.cn", - // "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn" - // } - - // use ssl - // "LDAP": { - // "ServerHost": "192.168.101.54", - // "ServerPort": 636, - // "UseSSL": true, - // "Credentials": { - // "DomainUserName": "administrator@yourdomain.com.cn", - // "Password": "yH.20190528" - // }, - // "SearchBase": "CN=Users,DC=yourdomain,DC=com,DC=cn", - // "DomainName": "yourdomain.com.cn", - // "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn" - // } - Configure(settings => - { - settings.ServerHost = "192.168.101.54"; - settings.ServerPort = 636; - settings.UseSsl = true; - settings.Credentials.DomainUserName = "administrator@yourdomain.com.cn"; - settings.Credentials.Password = "yH.20190528"; - settings.SearchBase = "DC=yourdomain,DC=com,DC=cn"; - settings.DomainName = "yourdomain.com.cn"; - settings.DomainDistinguishedName = "DC=yourdomain,DC=com,DC=cn"; - }); - } - } } -} \ No newline at end of file +} From d24d4c8403852eebb414b48f80fa567b8359bee2 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 7 Aug 2020 14:31:20 +0800 Subject: [PATCH 13/32] Add LdapSettingProvider. --- .../src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj | 10 ++- .../Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs | 44 ++++++++++++ .../Volo/Abp/Ldap/AbpLdapModule.cs | 31 ++++++++- .../Volo/Abp/Ldap/LdapManager.cs | 4 +- .../Volo/Abp/Ldap/LdapSettingNames.cs | 24 +++++++ .../Volo/Abp/Ldap/LdapSettingProvider.cs | 67 +++++++++++++++++++ .../Abp/Ldap/Localization/LdapResource.cs | 10 +++ .../Volo/Abp/Ldap/Localization/en.json | 28 ++++++++ .../Volo/Abp/Ldap/Localization/tr.json | 28 ++++++++ .../Volo/Abp/Ldap/Localization/zh-Hans.json | 28 ++++++++ .../Volo/Abp/Ldap/Localization/zh-Hant.json | 28 ++++++++ 11 files changed, 298 insertions(+), 4 deletions(-) create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingNames.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingProvider.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/LdapResource.cs create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/en.json create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/tr.json create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hans.json create mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hant.json diff --git a/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj index 5339a68da1..850bd29303 100644 --- a/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj +++ b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj @@ -17,9 +17,17 @@ - + + + + + + + + + diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs new file mode 100644 index 0000000000..8e744d414e --- /dev/null +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.Options; +using Volo.Abp.Settings; +using Volo.Abp.Threading; + +namespace Volo.Abp.Ldap +{ + public class AbpAbpLdapOptionsFactory : AbpOptionsFactory + { + protected ISettingProvider SettingProvider { get; } + + public AbpAbpLdapOptionsFactory( + IEnumerable> setups, + IEnumerable> postConfigures, + ISettingProvider settingProvider) + : base(setups, postConfigures) + { + SettingProvider = settingProvider; + } + + public override AbpLdapOptions Create(string name) + { + var options = base.Create(name); + + AsyncHelper.RunSync(() => OverrideOptionsAsync(options)); + + return options; + } + + protected virtual async Task OverrideOptionsAsync(AbpLdapOptions options) + { + options.ServerHost = await SettingProvider.GetOrNullAsync(LdapSettingNames.ServerHost) ?? options.ServerHost; + options.ServerPort = await SettingProvider.GetAsync(LdapSettingNames.ServerPort, options.ServerPort); + options.UseSsl = await SettingProvider.GetAsync(LdapSettingNames.UseSsl, options.UseSsl); + options.SearchBase = await SettingProvider.GetOrNullAsync(LdapSettingNames.SearchBase) ?? options.SearchBase; + options.DomainName = await SettingProvider.GetOrNullAsync(LdapSettingNames.DomainName) ?? options.DomainName; + options.DomainDistinguishedName = await SettingProvider.GetOrNullAsync(LdapSettingNames.DomainDistinguishedName) ?? options.DomainDistinguishedName; + options.Credentials.DomainUserName = await SettingProvider.GetOrNullAsync(LdapSettingNames.Credentials.DomainUserName) ?? options.Credentials.DomainUserName; + options.Credentials.Password = await SettingProvider.GetOrNullAsync(LdapSettingNames.Credentials.Password) ?? options.Credentials.Password; + } + } +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs index 216eee81b4..3978a1b1c1 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs @@ -1,14 +1,43 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using Volo.Abp.Ldap.Localization; +using Volo.Abp.Localization; using Volo.Abp.Modularity; +using Volo.Abp.Settings; +using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Ldap { + [DependsOn( + typeof(AbpSettingsModule), + typeof(AbpVirtualFileSystemModule), + typeof(AbpLocalizationModule))] public class AbpLdapModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { + context.Services.Replace(ServiceDescriptor.Transient, AbpAbpLdapOptionsFactory>()); + context.Services.Replace(ServiceDescriptor.Scoped, OptionsManager>()); + var configuration = context.Services.GetConfiguration(); - Configure(configuration.GetSection("LDAP")); + var ldapConfiguration = configuration["LDAP"]; + if (!ldapConfiguration.IsNullOrEmpty()) + { + Configure(configuration.GetSection("LDAP")); + } + + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Ldap/Localization"); + }); } } } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs index 77d8d04d91..acd7996c32 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs @@ -251,8 +251,8 @@ namespace Volo.Abp.Ldap protected virtual ILdapConnection GetConnection(string bindUserName = null, string bindUserPassword = null) { // bindUserName/bindUserPassword only be used when authenticate - bindUserName = bindUserName ?? LdapOptions.Credentials.DomainUserName; - bindUserPassword = bindUserPassword ?? LdapOptions.Credentials.Password; + bindUserName ??= LdapOptions.Credentials.DomainUserName; + bindUserPassword ??= LdapOptions.Credentials.Password; var ldapConnection = new LdapConnection() { SecureSocketLayer = LdapOptions.UseSsl }; if (LdapOptions.UseSsl) diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingNames.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingNames.cs new file mode 100644 index 0000000000..cfd851c12f --- /dev/null +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingNames.cs @@ -0,0 +1,24 @@ +namespace Volo.Abp.Ldap +{ + public static class LdapSettingNames + { + public const string ServerHost = "Abp.Ldap.ServerHost"; + + public const string ServerPort = "Abp.Ldap.ServerPort"; + + public const string UseSsl = "Abp.Ldap.UseSsl"; + + public const string SearchBase = "Abp.Ldap.SearchBase"; + + public const string DomainName = "Abp.Ldap.DomainName"; + + public const string DomainDistinguishedName = "Abp.Ldap.DomainDistinguishedName"; + + public static class Credentials + { + public const string DomainUserName = "Abp.Ldap.Credentials.DomainUserName"; + + public const string Password = "Abp.Ldap.Credentials.Password"; + } + } +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingProvider.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingProvider.cs new file mode 100644 index 0000000000..73dad5d73d --- /dev/null +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingProvider.cs @@ -0,0 +1,67 @@ +using Volo.Abp.Ldap.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Settings; + +namespace Volo.Abp.Ldap +{ + public class LdapSettingProvider : SettingDefinitionProvider + { + public override void Define(ISettingDefinitionContext context) + { + context.Add( + new SettingDefinition( + LdapSettingNames.ServerHost, + "", + L("DisplayName:Abp.Ldap.ServerHost"), + L("Description:Abp.Ldap.ServerHost")), + + new SettingDefinition( + LdapSettingNames.ServerPort, + "", + L("DisplayName:Abp.Ldap.ServerPort"), + L("Description:Abp.Ldap.ServerPort")), + + new SettingDefinition( + LdapSettingNames.UseSsl, + "", + L("DisplayName:Abp.Ldap.UseSsl"), + L("Description:Abp.Ldap.UseSsl")), + + new SettingDefinition( + LdapSettingNames.SearchBase, + "", + L("DisplayName:Abp.Ldap.SearchBase"), + L("Description:Abp.Ldap.SearchBase")), + + new SettingDefinition( + LdapSettingNames.DomainName, + "", + L("DisplayName:Abp.Ldap.DomainName"), + L("Description:Abp.Ldap.DomainName")), + + new SettingDefinition( + LdapSettingNames.DomainDistinguishedName, + "", + L("DisplayName:Abp.Ldap.DomainDistinguishedName"), + L("Description:Abp.Ldap.DomainDistinguishedName")), + + new SettingDefinition( + LdapSettingNames.Credentials.DomainUserName, + "", + L("DisplayName:Abp.Ldap.Credentials.DomainUserName"), + L("Description:Abp.Ldap.Credentials.DomainUserName")), + + new SettingDefinition( + LdapSettingNames.Credentials.Password, + "", + L("DisplayName:Abp.Ldap.Credentials.Password"), + L("Description:Abp.Ldap.Credentials.Password")) + ); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } + } +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/LdapResource.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/LdapResource.cs new file mode 100644 index 0000000000..e45b6797b5 --- /dev/null +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/LdapResource.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Localization; + +namespace Volo.Abp.Ldap.Localization +{ + [LocalizationResourceName("AbpLdap")] + public class LdapResource + { + + } +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/en.json b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/en.json new file mode 100644 index 0000000000..973e059684 --- /dev/null +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/en.json @@ -0,0 +1,28 @@ +{ + "culture": "en", + "texts": { + "DisplayName:Abp.Ldap.ServerHost": "ServerHost", + "Description:Abp.Ldap.ServerHost": "ServerHost", + + "DisplayName:Abp.Ldap.ServerPort": "ServerPort", + "Description:Abp.Ldap.ServerPort": "ServerPort", + + "DisplayName:Abp.Ldap.UseSsl": "UseSsl", + "Description:Abp.Ldap.UseSsl": "UseSsl", + + "DisplayName:Abp.Ldap.SearchBase": "SearchBase", + "Description:Abp.Ldap.SearchBase": "SearchBase", + + "DisplayName:Abp.Ldap.DomainName": "DomainName", + "Description:Abp.Ldap.DomainName": "DomainName", + + "DisplayName:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", + "Description:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", + + "DisplayName:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", + "Description:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", + + "DisplayName:Abp.Ldap.Credentials.Password": "Credentials Password", + "Description:Abp.Ldap.Credentials.Password": "Credentials Password", + } +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/tr.json b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/tr.json new file mode 100644 index 0000000000..eac7a9dbec --- /dev/null +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/tr.json @@ -0,0 +1,28 @@ +{ + "culture": "tr", + "texts": { + "DisplayName:Abp.Ldap.ServerHost": "ServerHost", + "Description:Abp.Ldap.ServerHost": "ServerHost", + + "DisplayName:Abp.Ldap.ServerPort": "ServerPort", + "Description:Abp.Ldap.ServerPort": "ServerPort", + + "DisplayName:Abp.Ldap.UseSsl": "UseSsl", + "Description:Abp.Ldap.UseSsl": "UseSsl", + + "DisplayName:Abp.Ldap.SearchBase": "SearchBase", + "Description:Abp.Ldap.SearchBase": "SearchBase", + + "DisplayName:Abp.Ldap.DomainName": "DomainName", + "Description:Abp.Ldap.DomainName": "DomainName", + + "DisplayName:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", + "Description:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", + + "DisplayName:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", + "Description:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", + + "DisplayName:Abp.Ldap.Credentials.Password": "Credentials Password", + "Description:Abp.Ldap.Credentials.Password": "Credentials Password", + } +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hans.json b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hans.json new file mode 100644 index 0000000000..94c0df37c1 --- /dev/null +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hans.json @@ -0,0 +1,28 @@ +{ + "culture": "zh-Hans", + "texts": { + "DisplayName:Abp.Ldap.ServerHost": "ServerHost", + "Description:Abp.Ldap.ServerHost": "ServerHost", + + "DisplayName:Abp.Ldap.ServerPort": "ServerPort", + "Description:Abp.Ldap.ServerPort": "ServerPort", + + "DisplayName:Abp.Ldap.UseSsl": "UseSsl", + "Description:Abp.Ldap.UseSsl": "UseSsl", + + "DisplayName:Abp.Ldap.SearchBase": "SearchBase", + "Description:Abp.Ldap.SearchBase": "SearchBase", + + "DisplayName:Abp.Ldap.DomainName": "DomainName", + "Description:Abp.Ldap.DomainName": "DomainName", + + "DisplayName:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", + "Description:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", + + "DisplayName:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", + "Description:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", + + "DisplayName:Abp.Ldap.Credentials.Password": "Credentials Password", + "Description:Abp.Ldap.Credentials.Password": "Credentials Password", + } +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hant.json b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hant.json new file mode 100644 index 0000000000..9822a9b6dc --- /dev/null +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hant.json @@ -0,0 +1,28 @@ +{ + "culture": "zh-Hant", + "texts": { + "DisplayName:Abp.Ldap.ServerHost": "ServerHost", + "Description:Abp.Ldap.ServerHost": "ServerHost", + + "DisplayName:Abp.Ldap.ServerPort": "ServerPort", + "Description:Abp.Ldap.ServerPort": "ServerPort", + + "DisplayName:Abp.Ldap.UseSsl": "UseSsl", + "Description:Abp.Ldap.UseSsl": "UseSsl", + + "DisplayName:Abp.Ldap.SearchBase": "SearchBase", + "Description:Abp.Ldap.SearchBase": "SearchBase", + + "DisplayName:Abp.Ldap.DomainName": "DomainName", + "Description:Abp.Ldap.DomainName": "DomainName", + + "DisplayName:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", + "Description:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", + + "DisplayName:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", + "Description:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", + + "DisplayName:Abp.Ldap.Credentials.Password": "Credentials Password", + "Description:Abp.Ldap.Credentials.Password": "Credentials Password", + } +} From 4c2aa3a72c532886dad3613fb81dfc99060a150c Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 7 Aug 2020 14:40:13 +0800 Subject: [PATCH 14/32] Fix build error. --- framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs index 3978a1b1c1..189af6eb41 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; using Volo.Abp.Ldap.Localization; From ed77133847968a660a4e673cf50b0e3c24706749 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 7 Aug 2020 21:22:06 +0800 Subject: [PATCH 15/32] Refactor the Volo.Abp.Ldap library. --- .../src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj | 2 +- .../Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs | 19 +- .../Volo/Abp/Ldap/AbpLdapModule.cs | 4 +- .../Volo/Abp/Ldap/AbpLdapOptions.cs | 17 +- .../OrganizationNotExistException.cs | 11 - .../Volo/Abp/Ldap/ILdapManager.cs | 67 +--- .../Volo/Abp/Ldap/LdapCredentials.cs | 9 - .../Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs | 34 -- .../Volo/Abp/Ldap/LdapManager.cs | 318 ++---------------- .../Volo/Abp/Ldap/LdapSettingNames.cs | 15 +- .../Volo/Abp/Ldap/LdapSettingProvider.cs | 39 +-- .../Volo/Abp/Ldap/Modeling/ILdapEntry.cs | 11 - .../Abp/Ldap/Modeling/ILdapOrganization.cs | 7 - .../Volo/Abp/Ldap/Modeling/ILdapUser.cs | 11 - .../Volo/Abp/Ldap/Modeling/LdapEntryBase.cs | 24 -- .../Abp/Ldap/Modeling/LdapOrganization.cs | 17 - .../Volo/Abp/Ldap/Modeling/LdapUser.cs | 25 -- framework/src/Volo.Abp.Ldap/readme.md | 171 ---------- .../Volo.Abp.Ldap.Tests.csproj | 1 + .../Volo/Abp/Ldap/AbpLdapTestModule.cs | 46 +-- .../Volo/Abp/Ldap/Authenticate_Tests.cs | 66 ---- .../Volo/Abp/Ldap/LdapHelps_Tests.cs | 84 ----- .../Volo/Abp/Ldap/LdapManager_Tests.cs | 179 +--------- .../Volo/Abp/Ldap/LdapOptions_Tests.cs | 21 ++ .../Volo/Abp/Ldap/LdapTestData.cs | 27 -- 25 files changed, 85 insertions(+), 1140 deletions(-) delete mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Exceptions/OrganizationNotExistException.cs delete mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapCredentials.cs delete mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs delete mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapEntry.cs delete mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapOrganization.cs delete mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapUser.cs delete mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapEntryBase.cs delete mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapOrganization.cs delete mode 100644 framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapUser.cs delete mode 100644 framework/src/Volo.Abp.Ldap/readme.md delete mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs delete mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapHelps_Tests.cs create mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapOptions_Tests.cs delete mode 100644 framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapTestData.cs diff --git a/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj index 850bd29303..849fe3ce3d 100644 --- a/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj +++ b/framework/src/Volo.Abp.Ldap/Volo.Abp.Ldap.csproj @@ -15,7 +15,7 @@ - + diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs index 8e744d414e..c3d3549a12 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.Options; using Volo.Abp.Options; @@ -31,14 +32,16 @@ namespace Volo.Abp.Ldap protected virtual async Task OverrideOptionsAsync(AbpLdapOptions options) { - options.ServerHost = await SettingProvider.GetOrNullAsync(LdapSettingNames.ServerHost) ?? options.ServerHost; + options.ServerHost = await GetStringValueOrDefault(LdapSettingNames.ServerHost) ?? options.ServerHost; options.ServerPort = await SettingProvider.GetAsync(LdapSettingNames.ServerPort, options.ServerPort); - options.UseSsl = await SettingProvider.GetAsync(LdapSettingNames.UseSsl, options.UseSsl); - options.SearchBase = await SettingProvider.GetOrNullAsync(LdapSettingNames.SearchBase) ?? options.SearchBase; - options.DomainName = await SettingProvider.GetOrNullAsync(LdapSettingNames.DomainName) ?? options.DomainName; - options.DomainDistinguishedName = await SettingProvider.GetOrNullAsync(LdapSettingNames.DomainDistinguishedName) ?? options.DomainDistinguishedName; - options.Credentials.DomainUserName = await SettingProvider.GetOrNullAsync(LdapSettingNames.Credentials.DomainUserName) ?? options.Credentials.DomainUserName; - options.Credentials.Password = await SettingProvider.GetOrNullAsync(LdapSettingNames.Credentials.Password) ?? options.Credentials.Password; + options.UserName = await GetStringValueOrDefault(LdapSettingNames.UserName) ?? options.UserName; + options.Password = await GetStringValueOrDefault(LdapSettingNames.Password) ?? options.Password; + } + + protected virtual async Task GetStringValueOrDefault(string name, string defaultValue = default) + { + var value = await SettingProvider.GetOrNullAsync(LdapSettingNames.ServerHost); + return value.IsNullOrWhiteSpace() ? defaultValue : value; } } } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs index 189af6eb41..c842d4d76b 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapModule.cs @@ -22,10 +22,10 @@ namespace Volo.Abp.Ldap context.Services.Replace(ServiceDescriptor.Scoped, OptionsManager>()); var configuration = context.Services.GetConfiguration(); - var ldapConfiguration = configuration["LDAP"]; + var ldapConfiguration = configuration["Ldap"]; if (!ldapConfiguration.IsNullOrEmpty()) { - Configure(configuration.GetSection("LDAP")); + Configure(configuration.GetSection("Ldap")); } Configure(options => diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapOptions.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapOptions.cs index 671d623ff7..38768581f4 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapOptions.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpLdapOptions.cs @@ -6,19 +6,8 @@ public int ServerPort { get; set; } - public bool UseSsl { get; set; } + public string UserName { get; set; } - public string SearchBase { get; set; } - - public string DomainName { get; set; } - - public string DomainDistinguishedName { get; set; } - - public LdapCredentials Credentials { get; set; } - - public AbpLdapOptions() - { - Credentials = new LdapCredentials(); - } + public string Password { get; set; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Exceptions/OrganizationNotExistException.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Exceptions/OrganizationNotExistException.cs deleted file mode 100644 index 9d7fb220cc..0000000000 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Exceptions/OrganizationNotExistException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Volo.Abp.Ldap.Exceptions -{ - public class OrganizationNotExistException : BusinessException - { - public OrganizationNotExistException(string distinguishedName) - : base("LDAP:000001", $"the organization distinguished named {distinguishedName} does not exist.") - { - - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs index f14e88b409..1943157fa8 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/ILdapManager.cs @@ -1,72 +1,17 @@ -using System.Collections.Generic; -using Volo.Abp.Ldap.Modeling; - -namespace Volo.Abp.Ldap +namespace Volo.Abp.Ldap { public interface ILdapManager { /// - /// query the specified organizations. - /// - /// filter: (&(name=xxx)(objectClass=organizationalUnit)) when name is not null - /// filter: (&(name=*)(objectClass=organizationalUnit)) when name is null - /// - /// - /// - /// - IList GetOrganizations(string name = null); - - /// - /// query the specified organization. - /// - /// filter: (&(distinguishedName=xxx)(objectClass=organizationalUnit)) when organizationName is not null - /// + /// Authenticate with default username/password /// - /// /// - LdapOrganization GetOrganization(string distinguishedName); - - void AddSubOrganization(string organizationName, LdapOrganization parentOrganization); - void AddSubOrganization(string organizationName, string parentDistinguishedName); - - /// - /// query the specified users. - /// - /// filter: (&(name=xxx)(objectCategory=person)(objectClass=user)) when name is not null - /// filter: (&(name=*)(objectCategory=person)(objectClass=user)) when name is null - /// - /// filter: (&(displayName=xxx)(objectCategory=person)(objectClass=user)) when displayName is not null - /// filter: (&(displayName=*)(objectCategory=person)(objectClass=user)) when displayName is null - /// - /// filter: (&(cn=xxx)(objectCategory=person)(objectClass=user)) when commonName is not null - /// filter: (&(cn=*)(objectCategory=person)(objectClass=user)) when commonName is null - /// - /// - /// - /// - /// - /// - IList GetUsers(string name = null, string displayName = null, string commonName = null); - - /// - /// query the specified User. - /// - /// filter: (&(distinguishedName=xxx)(objectCategory=person)(objectClass=user)) when distinguishedName is not null - /// - /// - /// - /// - LdapUser GetUser(string distinguishedName); - - void AddUserToOrganization(string userName, string password, LdapOrganization parentOrganization); - void AddUserToOrganization(string userName, string password, string parentDistinguishedName); + bool Authenticate(); /// - /// Authenticate + /// Authenticate with specified username/password /// - /// E.g administrator@yourdomain.com.cn - /// /// - bool Authenticate(string userDomainName, string password); + bool Authenticate(string username, string password); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapCredentials.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapCredentials.cs deleted file mode 100644 index a2d2eefd74..0000000000 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapCredentials.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Volo.Abp.Ldap -{ - public class LdapCredentials - { - public string DomainUserName { get; set; } - - public string Password { get; set; } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs deleted file mode 100644 index 49a60a964f..0000000000 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapHelps.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Abp.Ldap -{ - public static class LdapHelps - { - public static string BuildCondition(string name, string value) - { - return string.IsNullOrWhiteSpace(value) ? "" : $"({name}={value})"; - } - - public static string BuildFilter(Dictionary conditions) - { - if (null == conditions ) - { - conditions = new Dictionary(); - } - - if (conditions.Keys.Count == 0) - { - conditions.Add("objectClass", "*"); // add default condition - } - - var subFilter = string.Empty; - foreach (var keyValuePair in conditions) - { - subFilter += BuildCondition(keyValuePair.Key, keyValuePair.Value); - } - - return $"(&{subFilter})"; - } - - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs index acd7996c32..eeb7ce88b2 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs @@ -1,341 +1,61 @@ using System; using Microsoft.Extensions.Options; using Novell.Directory.Ldap; -using System.Collections.Generic; -using System.Text; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.DependencyInjection; -using Volo.Abp.ExceptionHandling; -using Volo.Abp.Ldap.Exceptions; -using Volo.Abp.Ldap.Modeling; namespace Volo.Abp.Ldap { public class LdapManager : ILdapManager, ITransientDependency { + public ILogger Logger { get; set; } protected AbpLdapOptions LdapOptions { get; } - protected IHybridServiceScopeFactory HybridServiceScopeFactory { get; } - private readonly string[] _attributes = + public LdapManager(IOptions ldapSettingsOptions) { - "objectCategory", "objectClass", "cn", "name", "distinguishedName", - "ou", - "sAMAccountName", "userPrincipalName", "telephoneNumber", "mail" - }; - - public LdapManager(IOptions ldapSettingsOptions, IHybridServiceScopeFactory hybridServiceScopeFactory) - { - HybridServiceScopeFactory = hybridServiceScopeFactory; LdapOptions = ldapSettingsOptions.Value; - } - - #region Organization - /// - /// query the specified organizations. - /// - /// filter: (&(name=xxx)(objectClass=organizationalUnit)) when name is not null - /// filter: (&(objectClass=organizationalUnit)) when name is null - /// - /// - /// - /// - public virtual IList GetOrganizations(string name = null) - { - var conditions = new Dictionary - { - {"name", name}, - {"objectClass", "organizationalUnit"}, - }; - return Query(LdapOptions.SearchBase, conditions); - } - - /// - /// query the specified organization. - /// - /// filter: (&(distinguishedName=xxx)(objectClass=organizationalUnit)) when organizationName is not null - /// - /// - /// - /// - public virtual LdapOrganization GetOrganization(string distinguishedName) - { - distinguishedName = Check.NotNullOrWhiteSpace(distinguishedName, nameof(distinguishedName)); - var conditions = new Dictionary - { - {"distinguishedName", distinguishedName}, - {"objectClass", "organizationalUnit"}, - }; - return QueryOne(LdapOptions.SearchBase, conditions); - } - - public virtual void AddSubOrganization(string organizationName, LdapOrganization parentOrganization) - { - organizationName = Check.NotNullOrWhiteSpace(organizationName, nameof(organizationName)); - var dn = $"OU={organizationName},{parentOrganization.DistinguishedName}"; - - var attributeSet = new LdapAttributeSet - { - new LdapAttribute("objectCategory", $"CN=Organizational-Unit,CN=Schema,CN=Configuration,{LdapOptions.DomainDistinguishedName}"), - new LdapAttribute("objectClass", new[] {"top", "organizationalUnit"}), - new LdapAttribute("name", organizationName), - }; - - var newEntry = new LdapEntry(dn, attributeSet); - - using (var ldapConnection = GetConnection()) - { - ldapConnection.Add(newEntry); - } - } - - public virtual void AddSubOrganization(string organizationName, string parentDistinguishedName) - { - organizationName = Check.NotNullOrWhiteSpace(organizationName, nameof(organizationName)); - parentDistinguishedName = - Check.NotNullOrWhiteSpace(parentDistinguishedName, nameof(parentDistinguishedName)); - - var parentOrganization = GetOrganization(parentDistinguishedName); - if (null == parentOrganization) - { - throw new OrganizationNotExistException(parentDistinguishedName); - } - - AddSubOrganization(organizationName, parentOrganization); - } - #endregion - - #region User - /// - /// query the specified users. - /// - /// filter: (&(name=xxx)(objectCategory=person)(objectClass=user)) when name is not null - /// filter: (&(objectCategory=person)(objectClass=user)) when name is null - /// - /// filter: (&(displayName=xxx)(objectCategory=person)(objectClass=user)) when displayName is not null - /// filter: (&(objectCategory=person)(objectClass=user)) when displayName is null - /// - /// filter: (&(cn=xxx)(objectCategory=person)(objectClass=user)) when commonName is not null - /// filter: (&(objectCategory=person)(objectClass=user)) when commonName is null - /// - /// - /// - /// - /// - /// - public virtual IList GetUsers(string name = null, string displayName = null, string commonName = null) - { - var conditions = new Dictionary - { - {"objectCategory", "person"}, - {"objectClass", "user"}, - {"name", name}, - {"displayName", displayName}, - {"cn", commonName}, - }; - return Query(LdapOptions.SearchBase, conditions); + Logger = NullLogger.Instance; } - /// - /// query the specified User. - /// - /// filter: (&(distinguishedName=xxx)(objectCategory=person)(objectClass=user)) when distinguishedName is not null - /// - /// - /// - /// - public virtual LdapUser GetUser(string distinguishedName) + public virtual bool Authenticate() { - distinguishedName = Check.NotNullOrWhiteSpace(distinguishedName, nameof(distinguishedName)); - var conditions = new Dictionary - { - {"objectCategory", "person"}, - {"objectClass", "user"}, - {"distinguishedName", distinguishedName}, - }; - return QueryOne(LdapOptions.SearchBase, conditions); + return Authenticate(LdapOptions.UserName, LdapOptions.Password); } - public virtual void AddUserToOrganization(string userName, string password, LdapOrganization parentOrganization) - { - var dn = $"CN={userName},{parentOrganization.DistinguishedName}"; - var mail = $"{userName}@{LdapOptions.DomainName}"; - var encodedBytes = SupportClass.ToSByteArray(Encoding.Unicode.GetBytes($"\"{password}\"")); - - var attributeSet = new LdapAttributeSet - { - new LdapAttribute("instanceType", "4"), - new LdapAttribute("objectCategory", $"CN=Person,CN=Schema,CN=Configuration,{LdapOptions.DomainDistinguishedName}"), - new LdapAttribute("objectClass", new[] {"top", "person", "organizationalPerson", "user"}), - new LdapAttribute("name", userName), - new LdapAttribute("cn", userName), - new LdapAttribute("sAMAccountName", userName), - new LdapAttribute("userPrincipalName", userName), - new LdapAttribute("sn", userName), - new LdapAttribute("displayName", userName), - new LdapAttribute("unicodePwd", encodedBytes), - new LdapAttribute("userAccountControl", "512"), - new LdapAttribute("mail", mail), - }; - var newEntry = new LdapEntry(dn, attributeSet); - - using (var ldapConnection = GetConnection()) - { - ldapConnection.Add(newEntry); - } - } - - public virtual void AddUserToOrganization(string userName, string password, string parentDistinguishedName) - { - var dn = $"CN={userName},{parentDistinguishedName}"; - var mail = $"{userName}@{LdapOptions.DomainName}"; - sbyte[] encodedBytes = SupportClass.ToSByteArray(Encoding.Unicode.GetBytes($"\"{password}\"")); - - var attributeSet = new LdapAttributeSet - { - new LdapAttribute("instanceType", "4"), - new LdapAttribute("objectCategory", $"CN=Person,CN=Schema,CN=Configuration,{LdapOptions.DomainDistinguishedName}"), - new LdapAttribute("objectClass", new[] {"top", "person", "organizationalPerson", "user"}), - new LdapAttribute("name", userName), - new LdapAttribute("cn", userName), - new LdapAttribute("sAMAccountName", userName), - new LdapAttribute("userPrincipalName", userName), - new LdapAttribute("sn", userName), - new LdapAttribute("displayName", userName), - new LdapAttribute("unicodePwd", encodedBytes), - new LdapAttribute("userAccountControl", "512"), - new LdapAttribute("mail", mail), - }; - var newEntry = new LdapEntry(dn, attributeSet); - - using (var ldapConnection = GetConnection()) - { - ldapConnection.Add(newEntry); - } - } - - #endregion - - #region Authenticate - - /// - /// Authenticate - /// - /// E.g administrator@yourdomain.com.cn - /// - /// - public virtual bool Authenticate(string userDomainName, string password) + public bool Authenticate(string username, string password) { try { - using (GetConnection(userDomainName, password)) - { - return true; - } + var conn = CreateLdapConnection(); + AuthenticateLdapConnection(conn, username,password); + return true; } catch (Exception ex) { - using (var scope = HybridServiceScopeFactory.CreateScope()) - { - scope.ServiceProvider - .GetRequiredService() - .NotifyAsync(ex); - } - + Logger.LogException(ex); return false; } } - #endregion - - protected virtual ILdapConnection GetConnection(string bindUserName = null, string bindUserPassword = null) + protected virtual ILdapConnection CreateLdapConnection() { - // bindUserName/bindUserPassword only be used when authenticate - bindUserName ??= LdapOptions.Credentials.DomainUserName; - bindUserPassword ??= LdapOptions.Credentials.Password; - - var ldapConnection = new LdapConnection() { SecureSocketLayer = LdapOptions.UseSsl }; - if (LdapOptions.UseSsl) - { - ldapConnection.UserDefinedServerCertValidationDelegate += (sender, certificate, chain, sslPolicyErrors) => true; - } + var ldapConnection = new LdapConnection(); + ConfigureLdapConnection(ldapConnection); ldapConnection.Connect(LdapOptions.ServerHost, LdapOptions.ServerPort); - - if (LdapOptions.UseSsl) - { - ldapConnection.Bind(LdapConnection.Ldap_V3, bindUserName, bindUserPassword); - } - else - { - ldapConnection.Bind(bindUserName, bindUserPassword); - } return ldapConnection; } - protected virtual IList Query(string searchBase, Dictionary conditions) where T : class, ILdapEntry - { - var filter = LdapHelps.BuildFilter(conditions); - - var result = new List(); - - using (var ldapConnection = GetConnection()) - { - var search = ldapConnection.Search(searchBase, LdapConnection.SCOPE_SUB, filter, - _attributes, false, null, null); - LdapMessage message; - while ((message = search.getResponse()) != null) - { - if (!(message is LdapSearchResult searchResultMessage)) - { - continue; - } - var entry = searchResultMessage.Entry; - if (typeof(T) == typeof(LdapOrganization)) - { - result.Add(new LdapOrganization(entry.getAttributeSet()) as T); - } + protected virtual void ConfigureLdapConnection(ILdapConnection connection) + { - if (typeof(T) == typeof(LdapUser)) - { - result.Add(new LdapUser(entry.getAttributeSet()) as T); - } - } - } - return result; } - protected virtual T QueryOne(string searchBase, Dictionary conditions) where T : class, ILdapEntry + protected virtual void AuthenticateLdapConnection(ILdapConnection connection, string username, string password) { - var filter = LdapHelps.BuildFilter(conditions); - - using (var ldapConnection = GetConnection()) - { - var search = ldapConnection.Search(searchBase, LdapConnection.SCOPE_SUB, filter, - _attributes, false, null, null); - - LdapMessage message; - while ((message = search.getResponse()) != null) - { - if (!(message is LdapSearchResult searchResultMessage)) - { - continue; - } - var entry = searchResultMessage.Entry; - if (typeof(T) == typeof(LdapOrganization)) - { - return new LdapOrganization(entry.getAttributeSet()) as T; - } - - if (typeof(T) == typeof(LdapUser)) - { - return new LdapUser(entry.getAttributeSet()) as T; - } - return null; - } - } - return null; + connection.Bind(username, password); } - } } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingNames.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingNames.cs index cfd851c12f..62fa58b49f 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingNames.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingNames.cs @@ -6,19 +6,8 @@ public const string ServerPort = "Abp.Ldap.ServerPort"; - public const string UseSsl = "Abp.Ldap.UseSsl"; + public const string UserName = "Abp.Ldap.UserName"; - public const string SearchBase = "Abp.Ldap.SearchBase"; - - public const string DomainName = "Abp.Ldap.DomainName"; - - public const string DomainDistinguishedName = "Abp.Ldap.DomainDistinguishedName"; - - public static class Credentials - { - public const string DomainUserName = "Abp.Ldap.Credentials.DomainUserName"; - - public const string Password = "Abp.Ldap.Credentials.Password"; - } + public const string Password = "Abp.Ldap.Password"; } } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingProvider.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingProvider.cs index 73dad5d73d..4549e1d8a0 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingProvider.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapSettingProvider.cs @@ -17,45 +17,22 @@ namespace Volo.Abp.Ldap new SettingDefinition( LdapSettingNames.ServerPort, - "", + "389", L("DisplayName:Abp.Ldap.ServerPort"), L("Description:Abp.Ldap.ServerPort")), new SettingDefinition( - LdapSettingNames.UseSsl, - "", - L("DisplayName:Abp.Ldap.UseSsl"), - L("Description:Abp.Ldap.UseSsl")), - - new SettingDefinition( - LdapSettingNames.SearchBase, - "", - L("DisplayName:Abp.Ldap.SearchBase"), - L("Description:Abp.Ldap.SearchBase")), - - new SettingDefinition( - LdapSettingNames.DomainName, - "", - L("DisplayName:Abp.Ldap.DomainName"), - L("Description:Abp.Ldap.DomainName")), - - new SettingDefinition( - LdapSettingNames.DomainDistinguishedName, - "", - L("DisplayName:Abp.Ldap.DomainDistinguishedName"), - L("Description:Abp.Ldap.DomainDistinguishedName")), - - new SettingDefinition( - LdapSettingNames.Credentials.DomainUserName, + LdapSettingNames.UserName, "", - L("DisplayName:Abp.Ldap.Credentials.DomainUserName"), - L("Description:Abp.Ldap.Credentials.DomainUserName")), + L("DisplayName:Abp.Ldap.UserName"), + L("Description:Abp.Ldap.UserName")), new SettingDefinition( - LdapSettingNames.Credentials.Password, + LdapSettingNames.Password, "", - L("DisplayName:Abp.Ldap.Credentials.Password"), - L("Description:Abp.Ldap.Credentials.Password")) + L("DisplayName:Abp.Ldap.Password"), + L("Description:Abp.Ldap.Password"), + isEncrypted: true) ); } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapEntry.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapEntry.cs deleted file mode 100644 index f15775fc06..0000000000 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapEntry.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Volo.Abp.Ldap.Modeling -{ - public interface ILdapEntry - { - string ObjectCategory { get; set; } - string[] ObjectClass { get; set; } - string Name { get; set; } - string DistinguishedName { get; set; } - string CommonName { get; set; } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapOrganization.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapOrganization.cs deleted file mode 100644 index 07c11000e8..0000000000 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapOrganization.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Volo.Abp.Ldap.Modeling -{ - public interface ILdapOrganization : ILdapEntry - { - string OrganizationUnit { get; set; } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapUser.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapUser.cs deleted file mode 100644 index 8ef68f6607..0000000000 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/ILdapUser.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Volo.Abp.Ldap.Modeling -{ - public interface ILdapUser : ILdapEntry - { - string SamAccountName { get; set; } - string UserPrincipalName { get; set; } - string DisplayName { get; set; } - string Email { get; set; } - string Phone { get; set; } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapEntryBase.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapEntryBase.cs deleted file mode 100644 index 6658a983d0..0000000000 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapEntryBase.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Novell.Directory.Ldap; - -namespace Volo.Abp.Ldap.Modeling -{ - public abstract class LdapEntryBase : ILdapEntry - { - public string ObjectCategory { get; set; } - public string[] ObjectClass { get; set; } - public string Name { get; set; } - public string CommonName { get; set; } - public string DistinguishedName { get; set; } - - protected LdapEntryBase() { } - - protected LdapEntryBase(LdapAttributeSet attributeSet) - { - ObjectCategory = attributeSet.getAttribute("objectCategory")?.StringValue; - ObjectClass = attributeSet.getAttribute("objectClass")?.StringValueArray; - Name = attributeSet.getAttribute("name")?.StringValue; - CommonName = attributeSet.getAttribute("cn")?.StringValue; - DistinguishedName = attributeSet.getAttribute("distinguishedName")?.StringValue; - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapOrganization.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapOrganization.cs deleted file mode 100644 index e401a2514d..0000000000 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapOrganization.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Novell.Directory.Ldap; - -namespace Volo.Abp.Ldap.Modeling -{ - public class LdapOrganization : LdapEntryBase, ILdapOrganization - { - public string OrganizationUnit { get; set; } - - public LdapOrganization() { } - - public LdapOrganization(LdapAttributeSet attributeSet) - : base(attributeSet) - { - OrganizationUnit = attributeSet.getAttribute("ou")?.StringValue; - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapUser.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapUser.cs deleted file mode 100644 index d9f554d512..0000000000 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Modeling/LdapUser.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Novell.Directory.Ldap; - -namespace Volo.Abp.Ldap.Modeling -{ - public class LdapUser : LdapEntryBase, ILdapUser - { - public string SamAccountName { get; set; } - public string UserPrincipalName { get; set; } - public string DisplayName { get; set; } - public string Email { get; set; } - public string Phone { get; set; } - - public LdapUser() { } - - public LdapUser( LdapAttributeSet attributeSet) - : base(attributeSet) - { - SamAccountName = attributeSet.getAttribute("sAMAccountName")?.StringValue; - UserPrincipalName = attributeSet.getAttribute("userPrincipalName")?.StringValue; - DisplayName = attributeSet.getAttribute("displayName")?.StringValue; - Email = attributeSet.getAttribute("mail")?.StringValue; - Phone = attributeSet.getAttribute("telephoneNumber")?.StringValue; - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ldap/readme.md b/framework/src/Volo.Abp.Ldap/readme.md deleted file mode 100644 index dd9b84087d..0000000000 --- a/framework/src/Volo.Abp.Ldap/readme.md +++ /dev/null @@ -1,171 +0,0 @@ -# Volo.Abp.Ldap - -# Only Authenticate(not read/write AD) - -## Configure - -add section in `appsettings.json` - -### use SSL - -```json -"LDAP": { - "ServerHost": "192.168.101.54", - "ServerPort": 636, - "UseSsl": true -} -``` - -### not use SSL - -```json -"LDAP": { - "ServerHost": "192.168.101.54", - "ServerPort": 389, - "UseSsl": false -} -``` - -## Authenticate - - Injecting `ILdapManager` into a class. For example: - -```csharp -public class TaxAppService : ApplicationService -{ - private readonly ILdapManager _ldapManager; - - public TaxAppService(ILdapManager ldapManager) - { - _ldapManager = ldapManager; - } - - public void Authenticate(string userName, string password) - { - var result = _ldapManager.Authenticate(userName, password); - } -} -``` - -- `userName` must be full domain name. E.g abc@abc.com - -# Read/Write AD - -## Configure - -### use SSL - -```json -"LDAP": { - "ServerHost": "192.168.101.54", - "ServerPort": 636, - "UseSsl": true, - "Credentials": { - "DomainUserName": "administrator@yourdomain.com.cn", - "Password": "yH.20190528" - }, - "SearchBase": "DC=yourdomain,DC=com,DC=cn", - "DomainName": "yourdomain.com.cn", - "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn" -} -``` - -### not use SSL - -```json -"LDAP": { - "ServerHost": "192.168.101.54", - "ServerPort": 389, - "UseSsl": false, - "Credentials": { - "DomainUserName": "administrator@yourdomain.com.cn", - "Password": "yH.20190528" - }, - "SearchBase": "DC=yourdomain,DC=com,DC=cn", - "DomainName": "yourdomain.com.cn", - "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn" -} -``` - -- `Credentials:DomainUserName` a administrator of AD. - -- `Credentials:Password` the password for the administrator. -- `SearchBase`: where search from AD. -- `DomainName`: name of you domain. no need `www`. -- `DomainDistinguishedName`: distinguished name of root domain. - -## Query Organizations - -```cs -// query all organizations -// filter: (&(objectClass=organizationalUnit)) -_ldapManager.GetOrganizations(); - -// query organizations by name -// filter: (&(name=abc)(objectClass=organizationalUnit)) -_ldapManager.GetOrganizations("abc"); - -``` - -## Query Organization - -```csharp -// query organization by distinguished name -// filter: (&(distinguishedName=abc)(objectClass=organizationalUnit)) -_ldapManager.GetOrganization("abc"); - -``` - -## Add Organization - -```csharp -// use LdapOrganization -_ldapManager.AddSubOrganization("nameA", parentOrganization); - -// or use OrganizationDistinguishedName -_ldapManager.AddSubOrganization("nameA", "OU=Domain Controllers,DC=yourdomain,DC=com,DC=cn"); -``` - -## Query Users - -```cs -// query all users -// filter: (&(objectCategory=person)(objectClass=user)) -_ldapManager.GetUsers(); - -// query organizations by name -// filter: (&(name=abc)(objectCategory=person)(objectClass=user)) -_ldapManager.GetUsers(name : "abc"); - -// query organizations by displayName -// filter: (&(displayName=abc)(objectCategory=person)(objectClass=user)) -_ldapManager.GetUsers(displayName : "abc"); - -// query organization by commonName -// filter: (&(cn=abc)(objectCategory=person)(objectClass=user)) -_ldapManager.GetUsers(commonName : "abc"); - -``` - -## Query User - -```csharp -// query a user by distinguished name -// filter: (&(distinguishedName=abc)(objectCategory=person)(objectClass=user)) -_ldapManager.GetUser("abc"); - -``` - -## Add User - -```csharp -// use LdapOrganization -_ldapManager.AddUserToOrganization("nameA", "passwordA", parentOrganization); - -// or use OrganizationDistinguishedName -_ldapManager.AddUserToOrganization("nameA", "passwordA", "OU=Domain Controllers,DC=yourdomain,DC=com,DC=cn"); -``` - -# More - -See [unit test](../../test/Volo.Abp.Ldap.Tests) \ No newline at end of file diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj b/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj index cea5e86688..d2db584347 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo.Abp.Ldap.Tests.csproj @@ -10,6 +10,7 @@ + diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs index f3932e0a05..7d6ba4d759 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs @@ -1,50 +1,20 @@ -using Volo.Abp.Modularity; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; namespace Volo.Abp.Ldap { - [DependsOn(typeof(AbpLdapModule))] + [DependsOn( + typeof(AbpAutofacModule), + typeof(AbpLdapModule), + typeof(AbpTestBaseModule) + )] public class AbpLdapTestModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - // not use ssl - // "LDAP": { - // "ServerHost": "192.168.101.54", - // "ServerPort": 389, - // "UseSSL": false, - // "Credentials": { - // "DomainUserName": "administrator@yourdomain.com.cn", - // "Password": "yH.20190528" - // }, - // "SearchBase": "CN=Users,DC=yourdomain,DC=com,DC=cn", - // "DomainName": "yourdomain.com.cn", - // "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn" - // } - - // use ssl - // "LDAP": { - // "ServerHost": "192.168.101.54", - // "ServerPort": 636, - // "UseSSL": true, - // "Credentials": { - // "DomainUserName": "administrator@yourdomain.com.cn", - // "Password": "yH.20190528" - // }, - // "SearchBase": "CN=Users,DC=yourdomain,DC=com,DC=cn", - // "DomainName": "yourdomain.com.cn", - // "DomainDistinguishedName": "DC=yourdomain,DC=com,DC=cn" - // } - Configure(settings => { - settings.ServerHost = "192.168.101.54"; - settings.ServerPort = 636; - settings.UseSsl = true; - settings.Credentials.DomainUserName = "administrator@yourdomain.com.cn"; - settings.Credentials.Password = "yH.20190528"; - settings.SearchBase = "DC=yourdomain,DC=com,DC=cn"; - settings.DomainName = "yourdomain.com.cn"; - settings.DomainDistinguishedName = "DC=yourdomain,DC=com,DC=cn"; + }); } } diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs deleted file mode 100644 index 46471893ce..0000000000 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/Authenticate_Tests.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using Shouldly; -using Volo.Abp.Modularity; -using Volo.Abp.Testing; -using Xunit; - -namespace Volo.Abp.Ldap -{ - public class Authenticate_Tests : AbpIntegratedTest - { - - private readonly ILdapManager _ldapManager; - private readonly LdapTestData _testData; - - public Authenticate_Tests() - { - // ReSharper disable once VirtualMemberCallInConstructor - _testData = GetRequiredService(); - _ldapManager = GetRequiredService(); - } - - [Fact(Skip = "need environment AD ")] - public void Authenticate() - { - var result = _ldapManager.Authenticate(_testData.AdministratorDomainName, _testData.AdministratorPassword); - - result.ShouldBeTrue(); - } - - [Fact(Skip = "need environment AD ")] - public void Authenticate_With_Wrong_Password() - { - var result = _ldapManager.Authenticate("NonExistentNameA", "PasswordA"); - - result.ShouldBeFalse(); - } - - [DependsOn(typeof(AbpLdapModule))] - public class TestModule : AbpModule - { - public override void ConfigureServices(ServiceConfigurationContext context) - { - // not use ssl - // "LDAP": { - // "ServerHost": "192.168.101.54", - // "ServerPort": 389, - // "UseSSL": false - // } - - // use ssl - // "LDAP": { - // "ServerHost": "192.168.101.54", - // "ServerPort": 636, - // "UseSSL": true - // } - Configure(settings => - { - settings.ServerHost = "192.168.101.54"; - settings.ServerPort = 636; - settings.UseSsl = true; - }); - } - } - } - -} diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapHelps_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapHelps_Tests.cs deleted file mode 100644 index 06d6834992..0000000000 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapHelps_Tests.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Collections.Generic; -using Shouldly; -using Xunit; - -namespace Volo.Abp.Ldap -{ - public class LdapHelps_Tests - { - - [Fact] - public void BuildCondition_With_Value() - { - // act - var res = LdapHelps.BuildCondition("objectClass", "testNameA"); - - // assert - res.ShouldBe("(objectClass=testNameA)"); - } - - [Fact] - public void BuildCondition_With_Null_Value() - { - // act - var res = LdapHelps.BuildCondition("objectClass", null); - - // assert - res.ShouldBeEmpty(); - } - - [Fact] - public void BuildCondition_With_Empty_Value() - { - // act - var res = LdapHelps.BuildCondition("objectClass", ""); - - // assert - res.ShouldBeEmpty(); - } - - [Fact] - public void BuildCondition_With_WhiteSpace_Value() - { - // act - var res = LdapHelps.BuildCondition("objectClass", " "); - - // assert - res.ShouldBeEmpty(); - } - - [Fact] - public void BuildFilter_With_Null_Condition() - { - // act - var res = LdapHelps.BuildFilter(null); - - // assert - res.ShouldBe("(&(objectClass=*))"); - } - - [Fact] - public void BuildFilter_With_Empty_Condition() - { - // act - var res = LdapHelps.BuildFilter(new Dictionary()); - - // assert - res.ShouldBe("(&(objectClass=*))"); - } - - [Fact] - public void BuildFilter_With_Condition() - { - // act - var conditions = new Dictionary - { - {"objectClass", "testClassA"}, {"objectCategory", "testCategoryA"}, {"name", null} - }; - var res = LdapHelps.BuildFilter(conditions); - - // assert - res.ShouldBe("(&(objectClass=testClassA)(objectCategory=testCategoryA))"); - } - } -} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs index 20382e5577..c793347f95 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs @@ -1,192 +1,19 @@ -using System; -using Shouldly; -using Volo.Abp.Testing; -using Xunit; +using Volo.Abp.Testing; namespace Volo.Abp.Ldap { public class LdapManager_Tests : AbpIntegratedTest { private readonly ILdapManager _ldapManager; - private readonly LdapTestData _testData; public LdapManager_Tests() { - _testData = GetRequiredService(); _ldapManager = GetRequiredService(); } - [Fact(Skip = "need environment AD ")] - public void GetOrganizations_With_Empty_Condition() + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) { - var result = _ldapManager.GetOrganizations(); - - result.ShouldNotBeNull(); - result.ShouldContain(e => e.Name == _testData.DomainControllersName); - result.ShouldContain(e => e.DistinguishedName == _testData.DomainControllersDistinguishedName); - } - - [Fact(Skip = "need environment AD ")] - public void GetOrganizations_With_Name() - { - var result = _ldapManager.GetOrganizations(_testData.DomainControllersName); - - result.ShouldNotBeNull(); - result.ShouldHaveSingleItem(); - result.ShouldContain(e => e.Name == _testData.DomainControllersName); - result.ShouldContain(e => e.DistinguishedName == _testData.DomainControllersDistinguishedName); - } - - [Fact(Skip = "need environment AD ")] - public void GetOrganizations_With_Non_Existent_Name() - { - var result = _ldapManager.GetOrganizations("NonExistentNameA"); - - result.ShouldNotBeNull(); - result.ShouldBeEmpty(); - } - - [Fact(Skip = "need environment AD ")] - public void GetOrganization() - { - var result = _ldapManager.GetOrganization(_testData.DomainControllersDistinguishedName); - - result.ShouldNotBeNull(); - result.Name.ShouldBe(_testData.DomainControllersName); - } - - [Fact(Skip = "need environment AD ")] - public void GetOrganization_With_Non_Existent_DistinguishedName() - { - var result = _ldapManager.GetOrganization("NonExistentNameA"); - - result.ShouldBeNull(); - } - - [Fact(Skip = "need environment AD ")] - public void GetUsers_With_Empty_Condition() - { - var result = _ldapManager.GetUsers(); - - result.ShouldNotBeNull(); - result.ShouldContain(e => e.Name == _testData.AdministratorName); - } - - [Fact(Skip = "need environment AD ")] - public void GetUsers_With_Name() - { - var result = _ldapManager.GetUsers(name: _testData.AdministratorName); - - result.ShouldNotBeNull(); - result.ShouldContain(e => e.Name == _testData.AdministratorName); - } - - [Fact(Skip = "need environment AD ")] - public void GetUsers_With_Non_Existent_Name() - { - var result = _ldapManager.GetUsers(name: "NonExistentNameA"); - - result.ShouldNotBeNull(); - result.ShouldBeEmpty(); - } - - [Fact(Skip = "need environment AD ")] - public void GetUsers_With_CommonName() - { - var result = _ldapManager.GetUsers(commonName: _testData.AdministratorName); - - result.ShouldNotBeNull(); - result.ShouldContain(e => e.Name == _testData.AdministratorName); - } - - [Fact(Skip = "need environment AD ")] - public void GetUsers_With_Non_Existent_CommonName() - { - var result = _ldapManager.GetUsers(commonName: "NonExistentNameA"); - - result.ShouldNotBeNull(); - result.ShouldBeEmpty(); - } - - [Fact(Skip = "need environment AD ")] - public void GetUsers_With_DisplayName() - { - var result = _ldapManager.GetUsers(displayName: _testData.AdministratorName); - - result.ShouldNotBeNull(); - // the administrator in AD. not have display name by default. - result.ShouldBeEmpty(); - } - - [Fact(Skip = "need environment AD ")] - public void GetUser() - { - var result = _ldapManager.GetUser(_testData.AdministratorDistinguishedName); - - result.ShouldNotBeNull(); - result.Name.ShouldBe(_testData.AdministratorName); - } - - [Fact(Skip = "need environment AD ")] - public void GetUser_With_Non_Existent_DistinguishedName() - { - var result = _ldapManager.GetOrganization("NonExistentNameA"); - - result.ShouldBeNull(); - } - - [Fact(Skip = "need environment AD ")] - public void Authenticate() - { - var result = _ldapManager.Authenticate(_testData.AdministratorDomainName, _testData.AdministratorPassword); - - result.ShouldBeTrue(); - } - - [Fact(Skip = "need environment AD ")] - public void Authenticate_With_Wrong_Password() - { - var result = _ldapManager.Authenticate("NonExistentNameA", "PasswordA"); - - result.ShouldBeFalse(); - } - - [Fact(Skip = "need environment AD ")] - public void AddSubOrganization() - { - var parentOrganization = _ldapManager.GetOrganization(_testData.DomainControllersDistinguishedName); - var randomName = $"Test_{DateTime.Now.Ticks}"; - - _ldapManager.AddSubOrganization(randomName, parentOrganization); - - var result = _ldapManager.GetOrganizations(randomName); - result.ShouldNotBeNull(); - result.ShouldContain(e => e.Name == randomName); - } - - [Fact(Skip = "need environment AD ")] - public void AddSubOrganization_With_DistinguishedName() - { - var randomName = $"Test_{DateTime.Now.Ticks}"; - - _ldapManager.AddSubOrganization(randomName, _testData.DomainControllersDistinguishedName); - - var result = _ldapManager.GetOrganizations(randomName); - result.ShouldNotBeNull(); - result.ShouldContain(e => e.Name == randomName); - } - - [Fact(Skip = "need environment AD ")] - public void AddOrganizationUser() - { - var parentOrganization = _ldapManager.GetOrganization(_testData.DomainControllersDistinguishedName); - var randomName = $"Test_{DateTime.Now:yyMMddHHmmss}"; - _ldapManager.AddUserToOrganization(randomName, _testData.AdministratorPassword, parentOrganization); - - var result = _ldapManager.GetUsers(randomName); - result.ShouldNotBeNull(); - result.ShouldContain(e=>e.Name == randomName); + options.UseAutofac(); } } - } diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapOptions_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapOptions_Tests.cs new file mode 100644 index 0000000000..8ec7ef94c6 --- /dev/null +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapOptions_Tests.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.Options; +using Shouldly; +using Volo.Abp.Testing; +using Xunit; + +namespace Volo.Abp.Ldap +{ + public class LdapOptions_Tests : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + + [Fact] + public void Should_Resolve_AbpAbpLdapOptionsFactory() + { + GetRequiredService>().ShouldBeOfType(typeof(AbpAbpLdapOptionsFactory)); + } + } +} diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapTestData.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapTestData.cs deleted file mode 100644 index 8224686daa..0000000000 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapTestData.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Volo.Abp.DependencyInjection; - -namespace Volo.Abp.Ldap -{ - public class LdapTestData : ISingletonDependency - { - public string AdministratorName { get; } = "Administrator"; - public string AdministratorPassword { get; } = "yH.20190528"; - public string AdministratorDistinguishedName { get; } = "CN=Administrator,CN=Users,DC=yourdomain,DC=com,DC=cn"; - public string AdministratorDomainName { get; } = "Administrator@yourdomain.com.cn"; - - public string DomainControllersName = "Domain Controllers"; - public string DomainControllersDistinguishedName = "OU=Domain Controllers,DC=yourdomain,DC=com,DC=cn"; - - public string RootDistinguishedName { get; } = "DC=yourdomain,DC=com,DC=cn"; - - public string Organization001Name { get; } = "Test_A"; - - public string Test001Name { get; } = "test001"; - public string Test001Password { get; } = "yH.20190528"; - public string Test001Email { get; } = "test001@yourdomain.com.cn"; - - public string Test002Name { get; } = "test002"; - public string Test002Password { get; } = "yH.20190528"; - public string Test002WrongPassword { get; } = "yH.20190529"; - } -} \ No newline at end of file From c49b62ae03368750603a67c2cd2a6bf05660028d Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Fri, 7 Aug 2020 21:57:11 +0800 Subject: [PATCH 16/32] Update ldap localization. --- .../Volo/Abp/Ldap/Localization/en.json | 28 +++++------------ .../Volo/Abp/Ldap/Localization/tr.json | 31 +++++-------------- .../Volo/Abp/Ldap/Localization/zh-Hans.json | 31 +++++-------------- .../Volo/Abp/Ldap/Localization/zh-Hant.json | 31 +++++-------------- 4 files changed, 32 insertions(+), 89 deletions(-) diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/en.json b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/en.json index 973e059684..e1894aa9d0 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/en.json +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/en.json @@ -1,28 +1,16 @@ { "culture": "en", "texts": { - "DisplayName:Abp.Ldap.ServerHost": "ServerHost", - "Description:Abp.Ldap.ServerHost": "ServerHost", + "DisplayName:Abp.Ldap.ServerHost": "Server host", + "Description:Abp.Ldap.ServerHost": "Server host", - "DisplayName:Abp.Ldap.ServerPort": "ServerPort", - "Description:Abp.Ldap.ServerPort": "ServerPort", + "DisplayName:Abp.Ldap.ServerPort": "Server port", + "Description:Abp.Ldap.ServerPort": "Server port", - "DisplayName:Abp.Ldap.UseSsl": "UseSsl", - "Description:Abp.Ldap.UseSsl": "UseSsl", + "DisplayName:Abp.Ldap.UserName": "Username", + "Description:Abp.Ldap.UserName": "Username", - "DisplayName:Abp.Ldap.SearchBase": "SearchBase", - "Description:Abp.Ldap.SearchBase": "SearchBase", - - "DisplayName:Abp.Ldap.DomainName": "DomainName", - "Description:Abp.Ldap.DomainName": "DomainName", - - "DisplayName:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", - "Description:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", - - "DisplayName:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", - "Description:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", - - "DisplayName:Abp.Ldap.Credentials.Password": "Credentials Password", - "Description:Abp.Ldap.Credentials.Password": "Credentials Password", + "DisplayName:Abp.Ldap.Password": "Password", + "Description:Abp.Ldap.Password": "Password" } } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/tr.json b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/tr.json index eac7a9dbec..078d403da8 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/tr.json +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/tr.json @@ -1,28 +1,13 @@ { "culture": "tr", "texts": { - "DisplayName:Abp.Ldap.ServerHost": "ServerHost", - "Description:Abp.Ldap.ServerHost": "ServerHost", - - "DisplayName:Abp.Ldap.ServerPort": "ServerPort", - "Description:Abp.Ldap.ServerPort": "ServerPort", - - "DisplayName:Abp.Ldap.UseSsl": "UseSsl", - "Description:Abp.Ldap.UseSsl": "UseSsl", - - "DisplayName:Abp.Ldap.SearchBase": "SearchBase", - "Description:Abp.Ldap.SearchBase": "SearchBase", - - "DisplayName:Abp.Ldap.DomainName": "DomainName", - "Description:Abp.Ldap.DomainName": "DomainName", - - "DisplayName:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", - "Description:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", - - "DisplayName:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", - "Description:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", - - "DisplayName:Abp.Ldap.Credentials.Password": "Credentials Password", - "Description:Abp.Ldap.Credentials.Password": "Credentials Password", + "DisplayName:Abp.Ldap.ServerHost": "Sunucu Ana Bilgisayarı", + "Description:Abp.Ldap.ServerHost": "Sunucu Ana Bilgisayarı", + "DisplayName:Abp.Ldap.ServerPort": "Sunucu portu", + "Description:Abp.Ldap.ServerPort": "Sunucu portu", + "DisplayName:Abp.Ldap.UserName": "Kullanıcı adı", + "Description:Abp.Ldap.UserName": "Kullanıcı adı", + "DisplayName:Abp.Ldap.Password": "parola", + "Description:Abp.Ldap.Password": "parola" } } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hans.json b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hans.json index 94c0df37c1..6cacad8746 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hans.json +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hans.json @@ -1,28 +1,13 @@ { "culture": "zh-Hans", "texts": { - "DisplayName:Abp.Ldap.ServerHost": "ServerHost", - "Description:Abp.Ldap.ServerHost": "ServerHost", - - "DisplayName:Abp.Ldap.ServerPort": "ServerPort", - "Description:Abp.Ldap.ServerPort": "ServerPort", - - "DisplayName:Abp.Ldap.UseSsl": "UseSsl", - "Description:Abp.Ldap.UseSsl": "UseSsl", - - "DisplayName:Abp.Ldap.SearchBase": "SearchBase", - "Description:Abp.Ldap.SearchBase": "SearchBase", - - "DisplayName:Abp.Ldap.DomainName": "DomainName", - "Description:Abp.Ldap.DomainName": "DomainName", - - "DisplayName:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", - "Description:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", - - "DisplayName:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", - "Description:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", - - "DisplayName:Abp.Ldap.Credentials.Password": "Credentials Password", - "Description:Abp.Ldap.Credentials.Password": "Credentials Password", + "DisplayName:Abp.Ldap.ServerHost": "服务器主机", + "Description:Abp.Ldap.ServerHost": "服务器主机", + "DisplayName:Abp.Ldap.ServerPort": "服务器端口", + "Description:Abp.Ldap.ServerPort": "服务器端口", + "DisplayName:Abp.Ldap.UserName": "用户名", + "Description:Abp.Ldap.UserName": "用户名", + "DisplayName:Abp.Ldap.Password": "密码", + "Description:Abp.Ldap.Password": "密码" } } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hant.json b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hant.json index 9822a9b6dc..1fcf263ed1 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hant.json +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/Localization/zh-Hant.json @@ -1,28 +1,13 @@ { "culture": "zh-Hant", "texts": { - "DisplayName:Abp.Ldap.ServerHost": "ServerHost", - "Description:Abp.Ldap.ServerHost": "ServerHost", - - "DisplayName:Abp.Ldap.ServerPort": "ServerPort", - "Description:Abp.Ldap.ServerPort": "ServerPort", - - "DisplayName:Abp.Ldap.UseSsl": "UseSsl", - "Description:Abp.Ldap.UseSsl": "UseSsl", - - "DisplayName:Abp.Ldap.SearchBase": "SearchBase", - "Description:Abp.Ldap.SearchBase": "SearchBase", - - "DisplayName:Abp.Ldap.DomainName": "DomainName", - "Description:Abp.Ldap.DomainName": "DomainName", - - "DisplayName:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", - "Description:Abp.Ldap.DomainDistinguishedName": "DomainDistinguishedName", - - "DisplayName:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", - "Description:Abp.Ldap.Credentials.DomainUserName": "Credentials DomainUserName", - - "DisplayName:Abp.Ldap.Credentials.Password": "Credentials Password", - "Description:Abp.Ldap.Credentials.Password": "Credentials Password", + "DisplayName:Abp.Ldap.ServerHost": "服務器主機", + "Description:Abp.Ldap.ServerHost": "服務器主機", + "DisplayName:Abp.Ldap.ServerPort": "服務器端口", + "Description:Abp.Ldap.ServerPort": "服務器端口", + "DisplayName:Abp.Ldap.UserName": "用戶名", + "Description:Abp.Ldap.UserName": "用戶名", + "DisplayName:Abp.Ldap.Password": "密碼", + "Description:Abp.Ldap.Password": "密碼" } } From 084a986297e1e6e203ee73bc28929074076728d7 Mon Sep 17 00:00:00 2001 From: EngincanV Date: Fri, 7 Aug 2020 18:26:17 +0300 Subject: [PATCH 17/32] Create passwordless-authentication.md --- .../passwordless-authentication.md | 279 ++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/passwordless-authentication.md diff --git a/docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/passwordless-authentication.md b/docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/passwordless-authentication.md new file mode 100644 index 0000000000..1f8be3a7f4 --- /dev/null +++ b/docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/passwordless-authentication.md @@ -0,0 +1,279 @@ +# Implementing Passwordless Authentication in ASP.NET Core Identity + +To allow a user login with a magic URL, you need to implement a custom token provider. +In this tutorial, we will show you how to add a custom token provider to authenticate a user with a link. + +> The completed sample is available: [passwordless-authentication.zip](https://abp.io/Account/Login?returnUrl=/api/download/samples/passwordless-authentication). To be able to download this sample, you need to hold an active ABP Commercial license. + +## Creating the Solution + +Before starting to the development, create a new solution named `PasswordlessAuthentication` and run it by following the [getting started tutorial](https://docs.abp.io/en/commercial/latest/getting-started?UI=MVC&DB=EF&Tiered=No). + +## Step-1 + +Create a class named **PasswordlessLoginProvider** in your ***.Web** project. + +**PasswordlessLoginProvider.cs** + +```csharp +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; + +namespace PasswordlessAuthentication.Web +{ + public class PasswordlessLoginProvider : TotpSecurityStampBasedTokenProvider + where TUser : class + { + public override Task CanGenerateTwoFactorTokenAsync(UserManager manager, TUser user) + { + return Task.FromResult(false); + } + + //We need to override this method as well. + public override async Task GetUserModifierAsync(string purpose, UserManager manager, TUser user) + { + var userId = await manager.GetUserIdAsync(user); + + return "PasswordlessLogin:" + purpose + ":" + userId; + } + } +} +``` +## Step-2 + +Create **IdentityBuilderExtensions.cs** in your ***.Web** project. + +We will use this extension method in `ConfigureServices`. + +```csharp +using Microsoft.AspNetCore.Identity; + +namespace PasswordlessAuthentication.Web +{ + public static class IdentityBuilderExtensions + { + public static IdentityBuilder AddPasswordlessLoginProvider(this IdentityBuilder builder) + { + var userType = builder.UserType; + var totpProvider = typeof(PasswordlessLoginProvider<>).MakeGenericType(userType); + return builder.AddTokenProvider("PasswordlessLoginProvider", totpProvider); + } + } +} +``` +## Step-3 + +Add the token provider to the `Identity` middleware. To do this, find the module class (eg: `PasswordlessAuthenticationWebModule.cs` in here) in your ***.Web** project and add the below into the `ConfigureServices()` method. + +```csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + //... + context.Services + .GetObject() + .AddDefaultTokenProviders() + .AddPasswordlessLoginProvider(); +} +``` + +## Step-4 + +We need to create a user interface to be able to generate the magic login link. To do this quickly, open your existing **Index.cshtml.cs** in your ***.Web** project. It's under `Pages` folder. And copy-paste the below content. + +**Index.cshtml.cs** + +```csharp +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Identity; + +namespace PasswordlessAuthentication.Web.Pages +{ + public class IndexModel : PasswordlessAuthenticationPageModel + { + protected IdentityUserManager UserManager { get; } + + private readonly IIdentityUserRepository _userRepository; + + public string PasswordlessLoginUrl { get; set; } + + public string Email { get; set; } + + public IndexModel(IdentityUserManager userManager, IIdentityUserRepository userRepository) + { + UserManager = userManager; + _userRepository = userRepository; + } + + public ActionResult OnGet() + { + if (!CurrentUser.IsAuthenticated) + { + return Redirect("/Account/Login"); + } + + return Page(); + } + + //added for passwordless authentication + public async Task OnPostGeneratePasswordlessTokenAsync() + { + var adminUser = await _userRepository.FindByNormalizedUserNameAsync("admin"); + + var token = await UserManager.GenerateUserTokenAsync(adminUser, "PasswordlessLoginProvider", + "passwordless-auth"); + + PasswordlessLoginUrl = Url.Action("Login", "Passwordless", + new {token = token, userId = adminUser.Id.ToString()}, Request.Scheme); + + return Page(); + } + } +} +``` + +We added `OnPostGeneratePasswordlessTokenAsync()` action to generate the link. We will generate a link for the **admin** user. Therefore, we injected `IIdentityUserRepository` to get admin user Id. Using the `UserManager.GenerateUserTokenAsync()` method, we generated a token. After that, we created the URL with the admin user Id and the token. Now we will show the `PasswordlessLoginUrl` on the page. + +## Step-5 + +Create a class named **PasswordlessAuthenticationMenus** under `Menus` folder in your ***.Web** project. And set the content as below. + +```csharp +namespace PasswordlessAuthentication.Web.Menus +{ + public class PasswordlessAuthenticationMenus + { + public const string GroupName = "PasswordlessAuthentication"; + + public const string Home = GroupName + ".Home"; + } +} +``` + +## Step-6 + +Open your **Index.cshtml** and set the content as below. We added a form that posts to `GeneratePasswordlessToken` action in the razor page. And it will set the `PasswordlessLoginUrl` field. + +```html +@page +@inject IHtmlLocalizer L +@using Microsoft.AspNetCore.Mvc.Localization +@using PasswordlessAuthentication.Localization +@using PasswordlessAuthentication.Web.Menus +@using Volo.Abp.AspNetCore.Mvc.UI.Layout +@model PasswordlessAuthentication.Web.Pages.IndexModel + +@{ + ViewBag.PageTitle = "Home"; +} +@inject IPageLayout PageLayout; +@{ + PageLayout.Content.Title = L["Home"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:Home"].Value); + PageLayout.Content.MenuItemName = PasswordlessAuthenticationMenus.Home; +} + + + +
+ + Generate passwordless token link + + @if (Model.PasswordlessLoginUrl != null) + { + + [@Model.PasswordlessLoginUrl](/en/commercial/latest/how-to/@Model.PasswordlessLoginUrl) + + } + +
+
+
+``` +## Step-7 + +We implemented token generation infrastructure, now it's time validate the token and let the user in. To do this create a folder named `Controllers` in your ***.Web** project and add the below controller. + +**PasswordlessController.cs** + +```csharp +using System; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Identity; +using Volo.Abp.Security.Claims; +using Volo.Abp.Users; + +namespace PasswordlessAuthentication.Web.Controllers +{ + public class PasswordlessController : AbpController + { + protected IdentityUserManager UserManager { get; } + + public PasswordlessController(IdentityUserManager userManager) + { + UserManager = userManager; + } + + public virtual async Task Login(string token, string userId) + { + var user = await UserManager.FindByIdAsync(userId); + + var isValid = await UserManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", token); + if (!isValid) + { + throw new UnauthorizedAccessException("The token " + token + " is not valid for the user " + userId); + } + + await UserManager.UpdateSecurityStampAsync(user); + + var roles = await UserManager.GetRolesAsync(user); + + var principal = new ClaimsPrincipal( + new ClaimsIdentity(CreateClaims(user, roles), IdentityConstants.ApplicationScheme) + ); + + await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, principal); + + return Redirect("/"); + } + + private static IEnumerable CreateClaims(IUser user, IEnumerable roles) + { + var claims = new List + { + new Claim("sub", user.Id.ToString()), + new Claim(AbpClaimTypes.UserId, user.Id.ToString()), + new Claim(AbpClaimTypes.Email, user.Email), + new Claim(AbpClaimTypes.UserName, user.UserName), + new Claim(AbpClaimTypes.EmailVerified, user.EmailConfirmed.ToString().ToLower()), + }; + + if (!string.IsNullOrWhiteSpace(user.PhoneNumber)) + { + claims.Add(new Claim(AbpClaimTypes.PhoneNumber, user.PhoneNumber)); + } + + foreach (var role in roles) + { + claims.Add(new Claim(AbpClaimTypes.Role, role)); + } + + return claims; + } + } +} +``` + +We created an endpoint for `/Passwordless/Login` that gets the token and the user Id. In this action, we find the user via repository and validate the token via `UserManager.VerifyUserTokenAsync()` method. If it's valid, we create claims of the user then call `HttpContext.SignInAsync` to be able to create an encrypted cookie and add it to the current response. Finally we redirect the page to the root URL. + +That's all! We created a passwordless login with 7 steps. + + + +> The completed sample is available: [passwordless-authentication.zip](https://abp.io/Account/Login?returnUrl=/api/download/samples/passwordless-authentication). To be able to download this sample, you need to hold an active ABP Commercial license. \ No newline at end of file From 61431132ab9a20a2cec55925d3c01c0d089387fe Mon Sep 17 00:00:00 2001 From: olicooper Date: Fri, 7 Aug 2020 17:27:03 +0100 Subject: [PATCH 18/32] Update Identity 'LockoutEnabled' localization in en.json --- .../Volo/Abp/Identity/Localization/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json index 8305ca9589..6bef6dcafe 100644 --- a/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json +++ b/modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/Localization/en.json @@ -25,7 +25,7 @@ "DisplayName:Email": "Email address", "DisplayName:PhoneNumber": "Phone number", "DisplayName:TwoFactorEnabled": "Two factor verification", - "DisplayName:LockoutEnabled": "Locking account after failed login attempts", + "DisplayName:LockoutEnabled": "Lock account after failed login attempts", "NewRole": "New role", "RoleName": "Role name", "CreationTime": "Creation time", From f6c80f765eed1f9854e5469c16f3476a50b0b5d0 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Sat, 8 Aug 2020 14:15:51 +0800 Subject: [PATCH 19/32] Fix OverrideOptionsAsync method logic error. --- .../Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs | 10 +++++----- .../src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs | 2 +- .../Volo/Abp/Ldap/AbpLdapTestModule.cs | 7 +++++-- .../Volo/Abp/Ldap/LdapManager_Tests.cs | 14 +++++++++++++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs index c3d3549a12..0f7117a42a 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/AbpAbpLdapOptionsFactory.cs @@ -32,15 +32,15 @@ namespace Volo.Abp.Ldap protected virtual async Task OverrideOptionsAsync(AbpLdapOptions options) { - options.ServerHost = await GetStringValueOrDefault(LdapSettingNames.ServerHost) ?? options.ServerHost; + options.ServerHost = await GetSettingOrDefaultValue(LdapSettingNames.ServerHost, options.ServerHost); options.ServerPort = await SettingProvider.GetAsync(LdapSettingNames.ServerPort, options.ServerPort); - options.UserName = await GetStringValueOrDefault(LdapSettingNames.UserName) ?? options.UserName; - options.Password = await GetStringValueOrDefault(LdapSettingNames.Password) ?? options.Password; + options.UserName = await GetSettingOrDefaultValue(LdapSettingNames.UserName, options.UserName); + options.Password = await GetSettingOrDefaultValue(LdapSettingNames.Password, options.Password); } - protected virtual async Task GetStringValueOrDefault(string name, string defaultValue = default) + protected virtual async Task GetSettingOrDefaultValue(string name, string defaultValue) { - var value = await SettingProvider.GetOrNullAsync(LdapSettingNames.ServerHost); + var value = await SettingProvider.GetOrNullAsync(name); return value.IsNullOrWhiteSpace() ? defaultValue : value; } } diff --git a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs index eeb7ce88b2..61b8f608d1 100644 --- a/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs +++ b/framework/src/Volo.Abp.Ldap/Volo/Abp/Ldap/LdapManager.cs @@ -29,7 +29,7 @@ namespace Volo.Abp.Ldap try { var conn = CreateLdapConnection(); - AuthenticateLdapConnection(conn, username,password); + AuthenticateLdapConnection(conn, username, password); return true; } catch (Exception ex) diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs index 7d6ba4d759..a9ab4a28ed 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/AbpLdapTestModule.cs @@ -12,9 +12,12 @@ namespace Volo.Abp.Ldap { public override void ConfigureServices(ServiceConfigurationContext context) { - Configure(settings => + Configure(options => { - + options.ServerHost = "192.168.0.3"; + options.ServerPort = 389; + options.UserName = "cn=admin,dc=abp,dc=io"; + options.Password = "123qwe"; }); } } diff --git a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs index c793347f95..4cfc8718c8 100644 --- a/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs +++ b/framework/test/Volo.Abp.Ldap.Tests/Volo/Abp/Ldap/LdapManager_Tests.cs @@ -1,4 +1,7 @@ -using Volo.Abp.Testing; +using System; +using Shouldly; +using Volo.Abp.Testing; +using Xunit; namespace Volo.Abp.Ldap { @@ -15,5 +18,14 @@ namespace Volo.Abp.Ldap { options.UseAutofac(); } + + [Fact(Skip = "Required Ldap environment")] + public void Authenticate() + { + _ldapManager.Authenticate().ShouldBe(true); + _ldapManager.Authenticate("cn=abp,dc=abp,dc=io", "123qwe").ShouldBe(true); + _ldapManager.Authenticate("NoExists", "123qwe").ShouldBe(false); + } + } } From 14e209985dcfd63b5830a1aeeafc5a77c37bf794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 8 Aug 2020 13:57:47 +0300 Subject: [PATCH 20/32] Rename and fix the Passwordless-Authentication article. --- ...passwordless-authentication.md => POST.md} | 555 +++++++++--------- 1 file changed, 276 insertions(+), 279 deletions(-) rename docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/{passwordless-authentication.md => POST.md} (88%) diff --git a/docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/passwordless-authentication.md b/docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/POST.md similarity index 88% rename from docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/passwordless-authentication.md rename to docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/POST.md index 1f8be3a7f4..1b7cef0867 100644 --- a/docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/passwordless-authentication.md +++ b/docs/en/Community-Articles/2020-08-07-Passwordless-Authentication/POST.md @@ -1,279 +1,276 @@ -# Implementing Passwordless Authentication in ASP.NET Core Identity - -To allow a user login with a magic URL, you need to implement a custom token provider. -In this tutorial, we will show you how to add a custom token provider to authenticate a user with a link. - -> The completed sample is available: [passwordless-authentication.zip](https://abp.io/Account/Login?returnUrl=/api/download/samples/passwordless-authentication). To be able to download this sample, you need to hold an active ABP Commercial license. - -## Creating the Solution - -Before starting to the development, create a new solution named `PasswordlessAuthentication` and run it by following the [getting started tutorial](https://docs.abp.io/en/commercial/latest/getting-started?UI=MVC&DB=EF&Tiered=No). - -## Step-1 - -Create a class named **PasswordlessLoginProvider** in your ***.Web** project. - -**PasswordlessLoginProvider.cs** - -```csharp -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity; - -namespace PasswordlessAuthentication.Web -{ - public class PasswordlessLoginProvider : TotpSecurityStampBasedTokenProvider - where TUser : class - { - public override Task CanGenerateTwoFactorTokenAsync(UserManager manager, TUser user) - { - return Task.FromResult(false); - } - - //We need to override this method as well. - public override async Task GetUserModifierAsync(string purpose, UserManager manager, TUser user) - { - var userId = await manager.GetUserIdAsync(user); - - return "PasswordlessLogin:" + purpose + ":" + userId; - } - } -} -``` -## Step-2 - -Create **IdentityBuilderExtensions.cs** in your ***.Web** project. - -We will use this extension method in `ConfigureServices`. - -```csharp -using Microsoft.AspNetCore.Identity; - -namespace PasswordlessAuthentication.Web -{ - public static class IdentityBuilderExtensions - { - public static IdentityBuilder AddPasswordlessLoginProvider(this IdentityBuilder builder) - { - var userType = builder.UserType; - var totpProvider = typeof(PasswordlessLoginProvider<>).MakeGenericType(userType); - return builder.AddTokenProvider("PasswordlessLoginProvider", totpProvider); - } - } -} -``` -## Step-3 - -Add the token provider to the `Identity` middleware. To do this, find the module class (eg: `PasswordlessAuthenticationWebModule.cs` in here) in your ***.Web** project and add the below into the `ConfigureServices()` method. - -```csharp -public override void ConfigureServices(ServiceConfigurationContext context) -{ - //... - context.Services - .GetObject() - .AddDefaultTokenProviders() - .AddPasswordlessLoginProvider(); -} -``` - -## Step-4 - -We need to create a user interface to be able to generate the magic login link. To do this quickly, open your existing **Index.cshtml.cs** in your ***.Web** project. It's under `Pages` folder. And copy-paste the below content. - -**Index.cshtml.cs** - -```csharp -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.Identity; - -namespace PasswordlessAuthentication.Web.Pages -{ - public class IndexModel : PasswordlessAuthenticationPageModel - { - protected IdentityUserManager UserManager { get; } - - private readonly IIdentityUserRepository _userRepository; - - public string PasswordlessLoginUrl { get; set; } - - public string Email { get; set; } - - public IndexModel(IdentityUserManager userManager, IIdentityUserRepository userRepository) - { - UserManager = userManager; - _userRepository = userRepository; - } - - public ActionResult OnGet() - { - if (!CurrentUser.IsAuthenticated) - { - return Redirect("/Account/Login"); - } - - return Page(); - } - - //added for passwordless authentication - public async Task OnPostGeneratePasswordlessTokenAsync() - { - var adminUser = await _userRepository.FindByNormalizedUserNameAsync("admin"); - - var token = await UserManager.GenerateUserTokenAsync(adminUser, "PasswordlessLoginProvider", - "passwordless-auth"); - - PasswordlessLoginUrl = Url.Action("Login", "Passwordless", - new {token = token, userId = adminUser.Id.ToString()}, Request.Scheme); - - return Page(); - } - } -} -``` - -We added `OnPostGeneratePasswordlessTokenAsync()` action to generate the link. We will generate a link for the **admin** user. Therefore, we injected `IIdentityUserRepository` to get admin user Id. Using the `UserManager.GenerateUserTokenAsync()` method, we generated a token. After that, we created the URL with the admin user Id and the token. Now we will show the `PasswordlessLoginUrl` on the page. - -## Step-5 - -Create a class named **PasswordlessAuthenticationMenus** under `Menus` folder in your ***.Web** project. And set the content as below. - -```csharp -namespace PasswordlessAuthentication.Web.Menus -{ - public class PasswordlessAuthenticationMenus - { - public const string GroupName = "PasswordlessAuthentication"; - - public const string Home = GroupName + ".Home"; - } -} -``` - -## Step-6 - -Open your **Index.cshtml** and set the content as below. We added a form that posts to `GeneratePasswordlessToken` action in the razor page. And it will set the `PasswordlessLoginUrl` field. - -```html -@page -@inject IHtmlLocalizer L -@using Microsoft.AspNetCore.Mvc.Localization -@using PasswordlessAuthentication.Localization -@using PasswordlessAuthentication.Web.Menus -@using Volo.Abp.AspNetCore.Mvc.UI.Layout -@model PasswordlessAuthentication.Web.Pages.IndexModel - -@{ - ViewBag.PageTitle = "Home"; -} -@inject IPageLayout PageLayout; -@{ - PageLayout.Content.Title = L["Home"].Value; - PageLayout.Content.BreadCrumb.Add(L["Menu:Home"].Value); - PageLayout.Content.MenuItemName = PasswordlessAuthenticationMenus.Home; -} - - - -
- - Generate passwordless token link - - @if (Model.PasswordlessLoginUrl != null) - { - - [@Model.PasswordlessLoginUrl](/en/commercial/latest/how-to/@Model.PasswordlessLoginUrl) - - } - -
-
-
-``` -## Step-7 - -We implemented token generation infrastructure, now it's time validate the token and let the user in. To do this create a folder named `Controllers` in your ***.Web** project and add the below controller. - -**PasswordlessController.cs** - -```csharp -using System; -using System.Collections.Generic; -using System.Security.Claims; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; -using Volo.Abp.Identity; -using Volo.Abp.Security.Claims; -using Volo.Abp.Users; - -namespace PasswordlessAuthentication.Web.Controllers -{ - public class PasswordlessController : AbpController - { - protected IdentityUserManager UserManager { get; } - - public PasswordlessController(IdentityUserManager userManager) - { - UserManager = userManager; - } - - public virtual async Task Login(string token, string userId) - { - var user = await UserManager.FindByIdAsync(userId); - - var isValid = await UserManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", token); - if (!isValid) - { - throw new UnauthorizedAccessException("The token " + token + " is not valid for the user " + userId); - } - - await UserManager.UpdateSecurityStampAsync(user); - - var roles = await UserManager.GetRolesAsync(user); - - var principal = new ClaimsPrincipal( - new ClaimsIdentity(CreateClaims(user, roles), IdentityConstants.ApplicationScheme) - ); - - await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, principal); - - return Redirect("/"); - } - - private static IEnumerable CreateClaims(IUser user, IEnumerable roles) - { - var claims = new List - { - new Claim("sub", user.Id.ToString()), - new Claim(AbpClaimTypes.UserId, user.Id.ToString()), - new Claim(AbpClaimTypes.Email, user.Email), - new Claim(AbpClaimTypes.UserName, user.UserName), - new Claim(AbpClaimTypes.EmailVerified, user.EmailConfirmed.ToString().ToLower()), - }; - - if (!string.IsNullOrWhiteSpace(user.PhoneNumber)) - { - claims.Add(new Claim(AbpClaimTypes.PhoneNumber, user.PhoneNumber)); - } - - foreach (var role in roles) - { - claims.Add(new Claim(AbpClaimTypes.Role, role)); - } - - return claims; - } - } -} -``` - -We created an endpoint for `/Passwordless/Login` that gets the token and the user Id. In this action, we find the user via repository and validate the token via `UserManager.VerifyUserTokenAsync()` method. If it's valid, we create claims of the user then call `HttpContext.SignInAsync` to be able to create an encrypted cookie and add it to the current response. Finally we redirect the page to the root URL. - -That's all! We created a passwordless login with 7 steps. - - - -> The completed sample is available: [passwordless-authentication.zip](https://abp.io/Account/Login?returnUrl=/api/download/samples/passwordless-authentication). To be able to download this sample, you need to hold an active ABP Commercial license. \ No newline at end of file +# Implementing Passwordless Authentication in ASP.NET Core Identity + +## Introduction + +To allow a user login with a magic URL, you need to implement a custom token provider. In this tutorial, we will show you how to add a custom token provider to authenticate a user with a link, instead of entering a password. + +### Source Code + +The completed sample is available on [the GitHub repository](https://github.com/abpframework/abp-samples/tree/master/PasswordlessAuthentication). + +## Creating the Solution + +Before starting to the development, create a new solution named `PasswordlessAuthentication` and run it by following the [getting started tutorial](https://docs.abp.io/en/abp/latest/Getting-Started?UI=MVC&DB=EF&Tiered=No). + +## Step-1 + +Create a class named **PasswordlessLoginProvider** in your ***.Web** project: + +```csharp +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; + +namespace PasswordlessAuthentication.Web +{ + public class PasswordlessLoginProvider : TotpSecurityStampBasedTokenProvider + where TUser : class + { + public override Task CanGenerateTwoFactorTokenAsync(UserManager manager, TUser user) + { + return Task.FromResult(false); + } + + //We need to override this method as well. + public override async Task GetUserModifierAsync(string purpose, UserManager manager, TUser user) + { + var userId = await manager.GetUserIdAsync(user); + + return "PasswordlessLogin:" + purpose + ":" + userId; + } + } +} +``` +## Step-2 + +Create **IdentityBuilderExtensions.cs** in your ***.Web** project. We will use this extension method in the `ConfigureServices`. + +```csharp +using Microsoft.AspNetCore.Identity; + +namespace PasswordlessAuthentication.Web +{ + public static class IdentityBuilderExtensions + { + public static IdentityBuilder AddPasswordlessLoginProvider(this IdentityBuilder builder) + { + var userType = builder.UserType; + var totpProvider = typeof(PasswordlessLoginProvider<>).MakeGenericType(userType); + return builder.AddTokenProvider("PasswordlessLoginProvider", totpProvider); + } + } +} +``` +## Step-3 + +Add the token provider to the `Identity` middleware. To do this, find the module class (eg: `PasswordlessAuthenticationWebModule.cs` in here) in your ***.Web** project and add the below into the `ConfigureServices()` method. + +```csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + //... + context.Services + .GetObject() + .AddDefaultTokenProviders() + .AddPasswordlessLoginProvider(); +} +``` + +## Step-4 + +We need to create a user interface to be able to generate the magic login link. To do this quickly, open your existing **Index.cshtml.cs** in your ***.Web** project. It's under `Pages` folder. And copy-paste the below content. + +**Index.cshtml.cs** + +```csharp +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Identity; + +namespace PasswordlessAuthentication.Web.Pages +{ + public class IndexModel : PasswordlessAuthenticationPageModel + { + protected IdentityUserManager UserManager { get; } + + private readonly IIdentityUserRepository _userRepository; + + public string PasswordlessLoginUrl { get; set; } + + public string Email { get; set; } + + public IndexModel(IdentityUserManager userManager, IIdentityUserRepository userRepository) + { + UserManager = userManager; + _userRepository = userRepository; + } + + public ActionResult OnGet() + { + if (!CurrentUser.IsAuthenticated) + { + return Redirect("/Account/Login"); + } + + return Page(); + } + + //added for passwordless authentication + public async Task OnPostGeneratePasswordlessTokenAsync() + { + var adminUser = await _userRepository.FindByNormalizedUserNameAsync("admin"); + + var token = await UserManager.GenerateUserTokenAsync(adminUser, "PasswordlessLoginProvider", + "passwordless-auth"); + + PasswordlessLoginUrl = Url.Action("Login", "Passwordless", + new {token = token, userId = adminUser.Id.ToString()}, Request.Scheme); + + return Page(); + } + } +} +``` + +We added `OnPostGeneratePasswordlessTokenAsync()` action to generate the link. We will generate a link for the **admin** user. Therefore, we injected `IIdentityUserRepository` to get admin user Id. Using the `UserManager.GenerateUserTokenAsync()` method, we generated a token. After that, we created the URL with the admin user Id and the token. Now we will show the `PasswordlessLoginUrl` on the page. + +## Step-5 + +Create a class named **PasswordlessAuthenticationMenus** under `Menus` folder in your ***.Web** project. And set the content as below. + +```csharp +namespace PasswordlessAuthentication.Web.Menus +{ + public class PasswordlessAuthenticationMenus + { + public const string GroupName = "PasswordlessAuthentication"; + + public const string Home = GroupName + ".Home"; + } +} +``` + +## Step-6 + +Open your **Index.cshtml** and set the content as below. We added a form that posts to `GeneratePasswordlessToken` action in the razor page. And it will set the `PasswordlessLoginUrl` field. + +```html +@page +@inject IHtmlLocalizer L +@using Microsoft.AspNetCore.Mvc.Localization +@using PasswordlessAuthentication.Localization +@using PasswordlessAuthentication.Web.Menus +@using Volo.Abp.AspNetCore.Mvc.UI.Layout +@model PasswordlessAuthentication.Web.Pages.IndexModel + +@{ + ViewBag.PageTitle = "Home"; +} +@inject IPageLayout PageLayout; +@{ + PageLayout.Content.Title = L["Home"].Value; + PageLayout.Content.BreadCrumb.Add(L["Menu:Home"].Value); + PageLayout.Content.MenuItemName = PasswordlessAuthenticationMenus.Home; +} + + + +
+ + Generate passwordless token link + + @if (Model.PasswordlessLoginUrl != null) + { + + [@Model.PasswordlessLoginUrl](/en/commercial/latest/how-to/@Model.PasswordlessLoginUrl) + + } + +
+
+
+``` +## Step-7 + +We implemented token generation infrastructure, now it's time validate the token and let the user in. To do this create a folder named `Controllers` in your ***.Web** project and create a controller, named **PasswordlessController** inside it: + +```csharp +using System; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Identity; +using Volo.Abp.Security.Claims; +using Volo.Abp.Users; + +namespace PasswordlessAuthentication.Web.Controllers +{ + public class PasswordlessController : AbpController + { + protected IdentityUserManager UserManager { get; } + + public PasswordlessController(IdentityUserManager userManager) + { + UserManager = userManager; + } + + public virtual async Task Login(string token, string userId) + { + var user = await UserManager.FindByIdAsync(userId); + + var isValid = await UserManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", token); + if (!isValid) + { + throw new UnauthorizedAccessException("The token " + token + " is not valid for the user " + userId); + } + + await UserManager.UpdateSecurityStampAsync(user); + + var roles = await UserManager.GetRolesAsync(user); + + var principal = new ClaimsPrincipal( + new ClaimsIdentity(CreateClaims(user, roles), IdentityConstants.ApplicationScheme) + ); + + await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, principal); + + return Redirect("/"); + } + + private static IEnumerable CreateClaims(IUser user, IEnumerable roles) + { + var claims = new List + { + new Claim("sub", user.Id.ToString()), + new Claim(AbpClaimTypes.UserId, user.Id.ToString()), + new Claim(AbpClaimTypes.Email, user.Email), + new Claim(AbpClaimTypes.UserName, user.UserName), + new Claim(AbpClaimTypes.EmailVerified, user.EmailConfirmed.ToString().ToLower()), + }; + + if (!string.IsNullOrWhiteSpace(user.PhoneNumber)) + { + claims.Add(new Claim(AbpClaimTypes.PhoneNumber, user.PhoneNumber)); + } + + foreach (var role in roles) + { + claims.Add(new Claim(AbpClaimTypes.Role, role)); + } + + return claims; + } + } +} +``` + +We created an endpoint for `/Passwordless/Login` that gets the token and the user Id. In this action, we find the user via repository and validate the token via `UserManager.VerifyUserTokenAsync()` method. If it's valid, we create claims of the user then call `HttpContext.SignInAsync` to be able to create an encrypted cookie and add it to the current response. Finally we redirect the page to the root URL. + +That's all! We created a passwordless login with 7 steps. + +## Source Code + +The completed sample is available on [the GitHub repository](https://github.com/abpframework/abp-samples/tree/master/PasswordlessAuthentication). \ No newline at end of file From 3fd143d04d093c32864e1c75c9b6f49274a289ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 8 Aug 2020 19:34:20 +0300 Subject: [PATCH 21/32] #4936 Add note for AppUser navigation property usage. --- docs/en/Entities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Entities.md b/docs/en/Entities.md index 538d298461..1f6e214efc 100644 --- a/docs/en/Entities.md +++ b/docs/en/Entities.md @@ -293,7 +293,7 @@ While you can manually implement any of the interfaces defined above, it is sugg All these base classes also have non-generic versions to take `AuditedEntity` and `FullAuditedAggregateRoot` to support the composite primary keys. -All these base classes also have `...WithUser` pairs, like `FullAuditedAggregateRootWithUser` and`FullAuditedAggregateRootWithUser`. This makes possible to add a navigation property to your user entity. However, it is not a good practice to add navigation properties between aggregate roots, so this usage is not suggested (unless you are using an ORM, like EF Core, that well supports this scenario and you really need it - otherwise remember that this approach doesn't work for NoSQL databases like MongoDB where you must truly implement the aggregate pattern). +All these base classes also have `...WithUser` pairs, like `FullAuditedAggregateRootWithUser` and `FullAuditedAggregateRootWithUser`. This makes possible to add a navigation property to your user entity. However, it is not a good practice to add navigation properties between aggregate roots, so this usage is not suggested (unless you are using an ORM, like EF Core, that well supports this scenario and you really need it - otherwise remember that this approach doesn't work for NoSQL databases like MongoDB where you must truly implement the aggregate pattern). Also, if you add navigation properties to the AppUser class that comes with the startup template, consider to handle (ignore/map) it on the migration dbcontext (see [the EF Core migration document](Entity-Framework-Core-Migrations.md)). ## Extra Properties From a0e6d998a49a10d49e5c40df0909fa8b73cc98f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 8 Aug 2020 20:42:59 +0300 Subject: [PATCH 22/32] Documented BasicAggregateRoot Class #4809 --- docs/en/Entities.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/en/Entities.md b/docs/en/Entities.md index 1f6e214efc..a5acba0546 100644 --- a/docs/en/Entities.md +++ b/docs/en/Entities.md @@ -234,6 +234,12 @@ ABP Framework does not force you to apply any DDD rule or patterns. However, it While it's not common (and not suggested) for aggregate roots, it is in fact possible to define composite keys in the same way as defined for the mentioned entities above. Use non-generic `AggregateRoot` base class in that case. +### BasicAggregateRoot Class + +`AggregateRoot` class implements the `IHasExtraProperties` and `IHasConcurrencyStamp` interfaces which brings two properties to the derived class. `IHasExtraProperties` makes the entity extensible (see the *Extra Properties* section below) and `IHasConcurrencyStamp` adds a `ConcurrencyStamp` property that is managed by the ABP Framework to implement the [optimistic concurrency](https://docs.microsoft.com/en-us/ef/core/saving/concurrency). In most cases, these are wanted features for aggregate roots. + +However, if you don't need these features, you can inherit from the `BasicAggregateRoot` (or `BasicAggregateRoot`) for your aggregate root. + ## Base Classes & Interfaces for Audit Properties There are some properties like `CreationTime`, `CreatorId`, `LastModificationTime`... which are very common in all applications. ABP Framework provides some interfaces and base classes to **standardize** these properties and also **sets their values automatically**. From 541324dbbe8021eecd2dd0bf6506e45f8a1ab1d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 8 Aug 2020 21:02:52 +0300 Subject: [PATCH 23/32] #4768 revise the information sentence. --- docs/en/Distributed-Event-Bus.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Distributed-Event-Bus.md b/docs/en/Distributed-Event-Bus.md index 0f2900e988..bd85613011 100644 --- a/docs/en/Distributed-Event-Bus.md +++ b/docs/en/Distributed-Event-Bus.md @@ -178,7 +178,7 @@ That's all. You can inject any service and perform any required logic here. A single event handler class can **subscribe to multiple events** but implementing the `IDistributedEventHandler` interface for each event type. -In your handler if you call a methods on a Repository you may find that you get an `ObjectDisposedException` being thrown. This will be because the unit of work being used by the Repository has been disposed in another context e.g. an ASP.net controller action. You will need to create a specific unit of work for your `HandleEventAsync` method. You can either use the `IUnitOfWorkManager.Begin` method or use the `UnitOfWorkAttribute` on the method. See the [Unit of work document](Unit-of-work.md) for more details. +If you perform **database operations** and use the [repositories](Repositories.md) inside the event handler, you may need to create a [unit of work](Unit-Of-Work.md), because some repository methods need to work inside an **active unit of work**. Make the handle method `virtual` and add a `[UnitOfWork]` attribute for the method, or manually use the `IUnitOfWorkManager` to create a unit of work scope. > The handler class must be registered to the dependency injection (DI). The sample above uses the `ITransientDependency` to accomplish it. See the [DI document](Dependency-Injection.md) for more options. From 4b966b14f3cb2df762b75d79c5819610b3f8e76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 8 Aug 2020 21:04:20 +0300 Subject: [PATCH 24/32] #4768 add UOW information to the local event bus too. --- docs/en/Local-Event-Bus.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/Local-Event-Bus.md b/docs/en/Local-Event-Bus.md index d0f494faea..d937a1caff 100644 --- a/docs/en/Local-Event-Bus.md +++ b/docs/en/Local-Event-Bus.md @@ -154,6 +154,8 @@ That's all. `MyHandler` is **automatically discovered** by the ABP Framework and * **Zero or more handlers** can subscribe to the same event. * A single event handler class can **subscribe to multiple events** but implementing the `ILocalEventHandler` interface for each event type. +If you perform **database operations** and use the [repositories](Repositories.md) inside the event handler, you may need to create a [unit of work](Unit-Of-Work.md), because some repository methods need to work inside an **active unit of work**. Make the handle method `virtual` and add a `[UnitOfWork]` attribute for the method, or manually use the `IUnitOfWorkManager` to create a unit of work scope. + > The handler class must be registered to the dependency injection (DI). The sample above uses the `ITransientDependency` to accomplish it. See the [DI document](Dependency-Injection.md) for more options. ## Transaction & Exception Behavior From 07a302f32a5d00bc9e9144e59d2314478f7e6f90 Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Sun, 9 Aug 2020 16:43:22 +0800 Subject: [PATCH 25/32] Update MyCompanyName.MyProjectName.MongoDB.csproj --- .../MyCompanyName.MyProjectName.MongoDB.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MyCompanyName.MyProjectName.MongoDB.csproj b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MyCompanyName.MyProjectName.MongoDB.csproj index 0cbda995f3..654c7a14f3 100644 --- a/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MyCompanyName.MyProjectName.MongoDB.csproj +++ b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MyCompanyName.MyProjectName.MongoDB.csproj @@ -3,7 +3,7 @@ - netstandart2.0 + netstandard2.0 MyCompanyName.MyProjectName From 03c149b111e538192929dc7ecb6b39db1167bb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 9 Aug 2020 12:28:35 +0300 Subject: [PATCH 26/32] Added links to the video tutorial. --- docs/en/Tutorials/Part-1.md | 10 ++++++++++ docs/en/Tutorials/Part-2.md | 10 ++++++++++ docs/en/Tutorials/Part-3.md | 10 ++++++++++ docs/en/Tutorials/Part-4.md | 10 ++++++++++ docs/en/Tutorials/Part-5.md | 10 ++++++++++ docs/en/Tutorials/images/youtube.png | Bin 0 -> 6430 bytes 6 files changed, 50 insertions(+) create mode 100644 docs/en/Tutorials/images/youtube.png diff --git a/docs/en/Tutorials/Part-1.md b/docs/en/Tutorials/Part-1.md index 3ee49e5e72..79947f3292 100644 --- a/docs/en/Tutorials/Part-1.md +++ b/docs/en/Tutorials/Part-1.md @@ -50,6 +50,16 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) +{{if UI == "MVC" && DB == "EF"}} + +### Video Tutorial + +This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. + +[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=cJzyIFfAlp8&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=1) + +{{end}} + ## Creating the Solution Before starting to the development, create a new solution named `Acme.BookStore` and run it by following the [getting started tutorial](../Getting-Started.md). diff --git a/docs/en/Tutorials/Part-2.md b/docs/en/Tutorials/Part-2.md index 1f3b6c84d1..681a99c6c1 100644 --- a/docs/en/Tutorials/Part-2.md +++ b/docs/en/Tutorials/Part-2.md @@ -50,6 +50,16 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) +{{if UI == "MVC" && DB == "EF"}} + +### Video Tutorial + +This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. + +[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=UDNlLiPiBiw&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=2) + +{{end}} + {{if UI == "MVC"}} ## Dynamic JavaScript Proxies diff --git a/docs/en/Tutorials/Part-3.md b/docs/en/Tutorials/Part-3.md index a0e839186c..93fcb9b6fe 100644 --- a/docs/en/Tutorials/Part-3.md +++ b/docs/en/Tutorials/Part-3.md @@ -50,6 +50,16 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) +{{if UI == "MVC" && DB == "EF"}} + +### Video Tutorial + +This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. + +[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=TLShZO8u2VE&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=3) + +{{end}} + {{if UI == "MVC"}} ## Creating a New Book diff --git a/docs/en/Tutorials/Part-4.md b/docs/en/Tutorials/Part-4.md index 1a82afa924..a6a7f25e99 100644 --- a/docs/en/Tutorials/Part-4.md +++ b/docs/en/Tutorials/Part-4.md @@ -50,6 +50,16 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) +{{if UI == "MVC" && DB == "EF"}} + +### Video Tutorial + +This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. + +[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=aidRB4YFDLM&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=4) + +{{end}} + ## Test Projects in the Solution This part covers the **server side** tests. There are several test projects in the solution: diff --git a/docs/en/Tutorials/Part-5.md b/docs/en/Tutorials/Part-5.md index c1deb21cab..c7bb832660 100644 --- a/docs/en/Tutorials/Part-5.md +++ b/docs/en/Tutorials/Part-5.md @@ -50,6 +50,16 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) +{{if UI == "MVC" && DB == "EF"}} + +### Video Tutorial + +This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. + +[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=1WsfMITN_Jk&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=5) + +{{end}} + ## Permissions ABP Framework provides an [authorization system](../Authorization.md) based on the ASP.NET Core's [authorization infrastructure](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction). One major feature added on top of the standard authorization infrastructure is the **permission system** which allows to define permissions and enable/disable per role, user or client. diff --git a/docs/en/Tutorials/images/youtube.png b/docs/en/Tutorials/images/youtube.png new file mode 100644 index 0000000000000000000000000000000000000000..cf9a67548dc7d2bce0872782814e9d325a1ca981 GIT binary patch literal 6430 zcmX9@1z1zx{~j=4QVs-0w}2o$M)xQQrRP8xU7|Dy5~C%gq`OsMv~-sU2uMkYlprCE zAo;)F-~aPGcf0p_wsY<|=RNP|eLv^T6J2$35(W|w2t=-_fz$_q@DhM~LkK?b$vOEq z4*0s`s`1nV1R}ln--QRt%%%f@=*BgXN`}7Ke{xdeiJp(lQ)#GI%_zKj)A zZVUE(J{6)vjkcS$nYM|ub>(M4@+T%u4LDCvi!#8(-@L2HgxsMd zi{iy!#R@~QE9pi4w{&UDWvxF?MudOJ9R&uVrdrE#{#~^12M{Yw!ZE^hu?lSW{PF0> zhhM@<2YAIn#60(=iZ(lXe>;8NDx9d#)9vrYW%v;$^YkxrH_f+9Q$LMP9p_BL## z7t7UeexGQKSVI$&BS+fY?E3eitREPW^}U>uBnjNkV(yDaD;V~{px>Na4ZgS7e0;E? zf}4+uin>9`u+w0TP!N8To?pX(pS-r8+K8r0(|GR&>lO8xlc<3aF7x$4w}H5Mubr9p zi|uk{oO-6la;oc&v4(DhR+?W!Jw7Npytq2T2F z#=+$ldR3*BMzkga z{Bd)vH|U1*>r`Oh*5nhjk+K5if^=a^e3QyiJAQtCm3Y_FZ6oBLV$Eb~62iO`jIg{a z7q-80vHyy-oJRgO+urmf@y{S@5Yk6oqH9wr7710sJgw}iWFL^l+b0&c>;X4tACnLk zK+H#3bv!u7R8X`0-5vg4GqarQvZB0m7v^;wogKLeE=u@Ao>fCnyn?b#@oa!FcvJ#{O-WCWlEW0oYN#ud1^FuAnwpxrx)gEq-@fV3xM!A9;%k*n_V@Q6 znt_PcoWU?)tt4JRH zvYqJA#{80A*rKw;mOSCT(!z$n+NLza{2Pe7aU8H)yB$|nQHdmH955RGSgs7IIQTDI za}BJ8@!6WXT7oQo)3?$~LT#v`Zhr|P7^h~BpYx{;Q>x`^i>Hp-t$lOB>+%?r8}u*- z@CTM~UcO$~dG&3QU5?qfGUR0^jSD%8;^eY!^*bPd`K~s;KAC)MTs}R)#$qY@2nt4H z#NqJu&CQ_O>$8-U6kwM9Pktx1o0Uz{lSQPbr-y}wZB3RP-`RDpK{+M-t+BMU)cz3^ z5D?((%x?l~Kr_?QZn!(i!x4y^tK%`V29j`&Buid(Jwq=qaaBFDb}}NBJox}wbA2zb z(}^PW&g;Jmrj0MWyu1>*=ouI?6B2}-XDT$4xtnFs_V$}4T4{n79cFrZdL|}kzbA^` zzNH9ZyExr}F)=aG(9pnO61HEcA4qnQ3Re4Z`Ns`vXF~`H59aI-W;>&sXFXs(ENCmM z!bc_B+uK&g8QP@)e1S3SCDqo7;y#O^EC0ee&k3EUb7XwH_m{5sgKk^vWF90E2>dT3 zUMxy_ZBL~Nn40^pgxe0MlC#Lt)oc*oWf{p3i!4v&8oItb6RYHxzxZ8bP^Rm48XX`1 zv+*UXmHy58`Z`-gbab?pU{O)gTEncliZ9H@))qkPtLpSmpFaIrXk?Xg?>p@L?$j{z zzsQw+<$iIp#VGNDjD%!WEOW?azBA~yBjA#OkuhgA^Bdd+&Jd?&ZEO3h*<;gt_j_VO z!oi@z4W-*X0Z<5Q;yDlagwkEg#zyfeeT6ysjl1RkSCz>v&%?vR3M1`2C1gUx`MK`~ zZE)!pKzd_2GH2(9YZc$Vyusmc)`M?HGsHGewkCh4BDg9Uvb2IxP<~UBq>K#XkB!UyPK#QbI~QDE z`|MCi zhIw?ee;Ya|zuj#CQ&Us>j?ems(V*Z00$4&27;jABZhwD5&h>4@SN%}awc$seo+rV01gLVR zUIbm-005V2gcu!}?%NI>9i9F5GZy8TU8=gdw!mw@y1Cs$NP7lAEwJO54TrM2y5sLP z))hu@otF!r$P)=B?gLcuA1a5N7CICUm{YSl<**6EmjB$F0-22~KzAZ$)}NqUu@FV4 z8q|xcF>#U=<@BT^WoVf7&{DfUCDEa5GmwSf+~a9uD)#BwMZk~@=6JIg1R&{eC0-xmXsO?d2_vQ&PgC1RqbHbcYhVrOL%84%tkWJq`kfx%6r?M-NA}x6~Pw zXEeer?HT3lfrR$O2z8{VrTP4sZveK;^|ndpDnoW5?|w-xF~oUBaZ+Eeg_BO4L^n6= z9uMXZ`sVFmNB?!`cL1!mqVzkYGq}b=$INL1Vvr%3=xcUGt5g z`#Sb5lFM>Q77$;fSy&lNjB8U6E$N**D^w(Z<7m>H*+H=^axE`^cD%j6IhLnBa(b~- zwNR3h^ZWO2pnKeaarvo&P)B(Ajn<97cuG#U-$ zp{Ck6=^WxwJF!)9!L;EV!TWbY(h)8URxYZls!?b%{+gN^U`OkQyScd)6cj|6H_{i# z<6H+XjrdYVtnI9$aGpih%bpnM8yIK~n2NEnf&K{gwh^lJ$s2qy zWRHzG8XtesS5Vc`!XVNrbf997Sz(9JNl*xy1&0!|b0~)q`g%4<+l|oW=ng(Cep^y>?b&3H;54yt~&)15f}`1^>TD^Io;50_v!iND{1o?imbZ0@Kcv7?YFYr zYi`lwrPloj@@MZEjuh|7eB6y6BOyv(T&D6$>iKsNL)`arHyuUA;N-owtSpI_?*C*T zXTpcJbj(dnW75N?8#A~x)hko)8J8QK3tdc-NEakdJ9&)^PE1dS`x;euENLVm+x!{8 zKI8-V!#Z#VR42=qVasm(H^k+ZXdX`kJ-u#QqS5+DMN(L$@$kcULpBw^ym_O0WGZq) znt9v-=912=Yiw*R>eUq{)l8al?aa*rcb>pFoxd6=BEdHHDk=ooGCY6vpSW)Q0OSoy z!0p|m`;#zM7ojhHhU^ghL$tRPcZ34O5g&xe8l6yYAN&>5YF@I$xg{5ZteL~?n@7bY zH`U_@1G*i8C^7Z-mnrXxj*Ig;+A45tkr_9-`)#+>hbw~Ala4;RkSU-5I^fym#)S+e zOkID#8~o-TJ10R?+|y!$^1EXA8~q$QlgxnLYvBcfcJ+8k9RBrqaT$Ivls8RWz+n5c zG8s_Spi(enpNDPL}q}ZB=TRWZYgU^EjA*enY3z2!K zaOC!YFGS*J*l=3EIkE4(LpAPXoovaP>gsV@t!%M|G>>0jXpCWmnyRzV*OB3Ee^N>A zvUKeS5^HKEB^ZN(>l@teuxb`R;a$`pv(A0wfao)yx(DH}hTykpxNw1UauQMqIn{e| z<)}!0{CcL{P06Vy9MG2?6&t(zp%_IMyAQN_|0z~=(sdOa%S`G#)5NIqW7D^>*Gin& z3x89)|D5n#0|Elg;*^~DMsi3s)Ga0s&|iukheLQ+$kg;9fn4vDCOZEfwxaT}cA zS<5#!3#|c+fyay*TE~ozgjVwK4DAi<;|i@QC$ISUIT^Q;HcRCsE{?D93LNJYF`V6H z(E3k37B~0{jh7bbc84qsN>EYOuxn-FyzUcf-P-^`6`Auu)g>TZD-&s)2sAf;Gb-my z80!0BS8J@@c1rc|bxrHK60v?$P}h4z~-TB64c3 zSQ?u9C$Tpanjzh6t5+3z3$2#Z1y88MXDagt`wobik%k3NBs*T>6A&2j(U_c*;|$eo zZEabDu4=5`{8-6gi+WmT=d#o`_ea$qyZq>E8PoZBnT`G840iU0Ty1Y370-ppBBxx` z7ffSB(sVz*2MFA#dBA)OUXrIg0@%YfM=&ExvNfJvRj((Kg~|*=36?#M9Z$XxkF5y8 zzei91=Dn?s-iqiP)-*5%u2Xb3y+f^5%?Yl<`OO`}Av1_RMApdZ}8Zv_ZY zn16UySp!IQbxtQ%Iln%#@wYcL0NqPHkRSi)A6?itO==LBNG#tvwH%d!risHeCbu={(OKV{d%CUtK#gE(cD4?owmX z%+%(d3@3#JUM~D(k@ozY^LUv?4~P5I=(6B_bM>lj?)B}>_2S~<$%$vZ;37dwOUunk znL;JHflo-Ns=E5%b0TL|`(Lz?5l!JRAQ{u~?@LP39bP=(<^A5^oc6;oymae$bBwc% zv;i&P9HyVgp+*(06v~F6<>N!9&+pU87?Uie4Gj$ugNKV zapqjUFsJb(5BZJ1UbL(G^}jg0nwl)tNgmD#S{BXN{gr0X;d{t2OFcI?*WBC;2naye z0ul8lDJjV>k|Kr;vm{HoajIT?m_Oxo+7nJX;R2YLmy1oeR9sThJRQz8q;UIhO!k|KtN=*yUoN3|GgTO9J}@uir4dVaV8Iau@6@l2RgF)E~ zz#uTI3v+UYmQhJOeE5)uN4;v6pPHm`J!;Sao_V@6dptKv2^O*cnmsb29l{nt!934d zBS=L>MMTa}Z#_tnHiQJYbO^8q1&zI6r3zFH2PbDQ!SI;H%~4vb_n#xxad!DAp6ZZL zAi?gI_UdBTnB;c@Y}Q%q`=TgsFJ?P8#`5B6<=z59tnG5I6+nYvyNx)*DDGKn`dk?^ zJH%?f-Vty=u~AXgX(v;H1NW1;b-sN0qI~;AoI%IVZlhEuYj>;+nEWMw9V+nQZrvDu zSGtHb1+z39aP>&*O5@9$%l)xDg`dBwximXYXH0=UuI>jSk$r$71T5y8zmaDTl+9}M zC4DG1MhS|Go>!?EsY*rlzJYE}G%c&1M}oLsX3++tbt2IkK;g0Cx&7IUr<4 zi2T|EcfZ#FekD)DI>MCV8ZcXc=e)hzRN&8TQ=f5a(A3lv>b!E-*H2pOSl*s4|M&0T zh#N3}C*QP$M26#86#%6;EPna!fx&8`cL>1oQc_aDgu97$u*&+nIyr6cRCVt8x)$+n zAFT9NcxyX4I_hTbUtL|5n^cLK@=-?v+~I9esZVWWXz02AIT5IKNcqX{oL*#z*$blU z-(IaoO?#Elo}7TMnvFq>YWu>(^I62_iW;S#^wD@KYCl@TwK6TCs4;DU3&i z^6wu41}^!SO1(0c@E0pXEE z5jrydBx+Q}ID8!bWNJ+zR!uk~zmhywt$MD@0URAt%3VE|U$j<(ban~9ePG-rQX1cW z|1pzL67#)or-t|{NiXRq Date: Sun, 9 Aug 2020 12:32:13 +0300 Subject: [PATCH 27/32] Update Part-1.md --- docs/en/Tutorials/Part-1.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/Tutorials/Part-1.md b/docs/en/Tutorials/Part-1.md index 79947f3292..06e534f506 100644 --- a/docs/en/Tutorials/Part-1.md +++ b/docs/en/Tutorials/Part-1.md @@ -56,7 +56,9 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. -[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=cJzyIFfAlp8&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=1) + + + {{end}} From 75ad8c42ae75ff50cdc09890ff18238c4b7e1ada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 9 Aug 2020 12:41:26 +0300 Subject: [PATCH 28/32] Fix youtube links. --- docs/en/Tutorials/Part-1.md | 8 ++------ docs/en/Tutorials/Part-2.md | 6 ++---- docs/en/Tutorials/Part-3.md | 6 ++---- docs/en/Tutorials/Part-4.md | 6 ++---- docs/en/Tutorials/Part-5.md | 6 ++---- 5 files changed, 10 insertions(+), 22 deletions(-) diff --git a/docs/en/Tutorials/Part-1.md b/docs/en/Tutorials/Part-1.md index 06e534f506..5814bb606a 100644 --- a/docs/en/Tutorials/Part-1.md +++ b/docs/en/Tutorials/Part-1.md @@ -45,7 +45,7 @@ This tutorial is organized as the following parts; ### Download the Source Code -This tutorials has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: +This tutorial has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) @@ -54,11 +54,7 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe ### Video Tutorial -This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. - - - - +This part is also recorded as a video tutorial and **published on YouTube**. {{end}} diff --git a/docs/en/Tutorials/Part-2.md b/docs/en/Tutorials/Part-2.md index 681a99c6c1..c947f4495d 100644 --- a/docs/en/Tutorials/Part-2.md +++ b/docs/en/Tutorials/Part-2.md @@ -45,7 +45,7 @@ This tutorial is organized as the following parts; ### Download the Source Code -This tutorials has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: +This tutorial has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) @@ -54,9 +54,7 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe ### Video Tutorial -This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. - -[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=UDNlLiPiBiw&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=2) +This part is also recorded as a video tutorial and **published on YouTube**. {{end}} diff --git a/docs/en/Tutorials/Part-3.md b/docs/en/Tutorials/Part-3.md index 93fcb9b6fe..13aa5df8c3 100644 --- a/docs/en/Tutorials/Part-3.md +++ b/docs/en/Tutorials/Part-3.md @@ -45,7 +45,7 @@ This tutorial is organized as the following parts; ### Download the Source Code -This tutorials has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: +This tutorial has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) @@ -54,9 +54,7 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe ### Video Tutorial -This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. - -[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=TLShZO8u2VE&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=3) +This part is also recorded as a video tutorial and **published on YouTube**. {{end}} diff --git a/docs/en/Tutorials/Part-4.md b/docs/en/Tutorials/Part-4.md index a6a7f25e99..2868df8ba6 100644 --- a/docs/en/Tutorials/Part-4.md +++ b/docs/en/Tutorials/Part-4.md @@ -45,7 +45,7 @@ This tutorial is organized as the following parts; ### Download the Source Code -This tutorials has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: +This tutorial has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) @@ -54,9 +54,7 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe ### Video Tutorial -This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. - -[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=aidRB4YFDLM&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=4) +This part is also recorded as a video tutorial and **published on YouTube**. {{end}} diff --git a/docs/en/Tutorials/Part-5.md b/docs/en/Tutorials/Part-5.md index c7bb832660..5b2dfc0431 100644 --- a/docs/en/Tutorials/Part-5.md +++ b/docs/en/Tutorials/Part-5.md @@ -45,7 +45,7 @@ This tutorial is organized as the following parts; ### Download the Source Code -This tutorials has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: +This tutorial has multiple versions based on your **UI** and **Database** preferences. We've prepared two combinations of the source code to be downloaded: * [MVC (Razor Pages) UI with EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore) * [Angular UI with MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb) @@ -54,9 +54,7 @@ This tutorials has multiple versions based on your **UI** and **Database** prefe ### Video Tutorial -This tutorial part is also recorded as a video tutorial. Click to the image below to watch the video tutorial on YouTube. - -[![youtube](images/youtube.png)](https://www.youtube.com/watch?v=1WsfMITN_Jk&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=5) +This part is also recorded as a video tutorial and **published on YouTube**. {{end}} From f0b27116cf59ccc250fc80b3a3bbfacde8b535ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 9 Aug 2020 18:28:27 +0300 Subject: [PATCH 29/32] Add appsettings.json tp the console sample. --- .../MyCompanyName.MyProjectName.csproj | 8 ++++++++ .../src/MyCompanyName.MyProjectName/appsettings.json | 2 ++ 2 files changed, 10 insertions(+) create mode 100644 templates/console/src/MyCompanyName.MyProjectName/appsettings.json diff --git a/templates/console/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj b/templates/console/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj index c8d78bfc2c..b8f062a83d 100644 --- a/templates/console/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj +++ b/templates/console/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj @@ -19,4 +19,12 @@
+ + + + PreserveNewest + Always + + + diff --git a/templates/console/src/MyCompanyName.MyProjectName/appsettings.json b/templates/console/src/MyCompanyName.MyProjectName/appsettings.json new file mode 100644 index 0000000000..0f530c147c --- /dev/null +++ b/templates/console/src/MyCompanyName.MyProjectName/appsettings.json @@ -0,0 +1,2 @@ +{ +} From c07b29c55797ef628914f83fae1c30aed2a96972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 9 Aug 2020 18:59:57 +0300 Subject: [PATCH 30/32] Resolved #5006: Console applications should participate to the main host builder --- .../MyCompanyName.MyProjectName.csproj | 3 +- .../MyProjectNameHostedService.cs | 41 +++++++++++-------- .../MyProjectNameModule.cs | 10 ++++- .../MyCompanyName.MyProjectName/Program.cs | 9 +++- .../appsettings.json | 1 + 5 files changed, 43 insertions(+), 21 deletions(-) diff --git a/templates/console/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj b/templates/console/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj index b8f062a83d..513dfb9fc7 100644 --- a/templates/console/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj +++ b/templates/console/src/MyCompanyName.MyProjectName/MyCompanyName.MyProjectName.csproj @@ -13,14 +13,13 @@ - + - PreserveNewest Always diff --git a/templates/console/src/MyCompanyName.MyProjectName/MyProjectNameHostedService.cs b/templates/console/src/MyCompanyName.MyProjectName/MyProjectNameHostedService.cs index 5c5c9d89ee..6ddcd6630d 100644 --- a/templates/console/src/MyCompanyName.MyProjectName/MyProjectNameHostedService.cs +++ b/templates/console/src/MyCompanyName.MyProjectName/MyProjectNameHostedService.cs @@ -1,34 +1,41 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Serilog; using Volo.Abp; namespace MyCompanyName.MyProjectName { public class MyProjectNameHostedService : IHostedService { - public Task StartAsync(CancellationToken cancellationToken) + private readonly IAbpApplicationWithExternalServiceProvider _application; + private readonly IServiceProvider _serviceProvider; + private readonly HelloWorldService _helloWorldService; + + public MyProjectNameHostedService( + IAbpApplicationWithExternalServiceProvider application, + IServiceProvider serviceProvider, + HelloWorldService helloWorldService) { - using (var application = AbpApplicationFactory.Create(options => - { - options.UseAutofac(); //Autofac integration - options.Services.AddLogging(c => c.AddSerilog()); - })) - { - application.Initialize(); + _application = application; + _serviceProvider = serviceProvider; + _helloWorldService = helloWorldService; + } - //Resolve a service and use it - var helloWorldService = application.ServiceProvider.GetService(); - helloWorldService.SayHello(); + public Task StartAsync(CancellationToken cancellationToken) + { + _application.Initialize(_serviceProvider); - application.Shutdown(); - } + _helloWorldService.SayHello(); return Task.CompletedTask; } - public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public Task StopAsync(CancellationToken cancellationToken) + { + _application.Shutdown(); + + return Task.CompletedTask; + } } } diff --git a/templates/console/src/MyCompanyName.MyProjectName/MyProjectNameModule.cs b/templates/console/src/MyCompanyName.MyProjectName/MyProjectNameModule.cs index 9938981484..2d5e600971 100644 --- a/templates/console/src/MyCompanyName.MyProjectName/MyProjectNameModule.cs +++ b/templates/console/src/MyCompanyName.MyProjectName/MyProjectNameModule.cs @@ -1,4 +1,6 @@ -using Volo.Abp.Autofac; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Volo.Abp.Autofac; using Volo.Abp.Modularity; namespace MyCompanyName.MyProjectName @@ -9,6 +11,12 @@ namespace MyCompanyName.MyProjectName )] public class MyProjectNameModule : AbpModule { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + var hostEnvironment = context.Services.GetSingletonInstance(); + context.Services.AddHostedService(); + } } } diff --git a/templates/console/src/MyCompanyName.MyProjectName/Program.cs b/templates/console/src/MyCompanyName.MyProjectName/Program.cs index b095d0db73..2e913e7d4b 100644 --- a/templates/console/src/MyCompanyName.MyProjectName/Program.cs +++ b/templates/console/src/MyCompanyName.MyProjectName/Program.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog; @@ -43,9 +44,15 @@ namespace MyCompanyName.MyProjectName internal static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) + .UseAutofac() + .UseSerilog() + .ConfigureAppConfiguration((context, config) => + { + //setup your additional configuration sources + }) .ConfigureServices((hostContext, services) => { - services.AddHostedService(); + services.AddApplication(); }); } } diff --git a/templates/console/src/MyCompanyName.MyProjectName/appsettings.json b/templates/console/src/MyCompanyName.MyProjectName/appsettings.json index 0f530c147c..d177980a92 100644 --- a/templates/console/src/MyCompanyName.MyProjectName/appsettings.json +++ b/templates/console/src/MyCompanyName.MyProjectName/appsettings.json @@ -1,2 +1,3 @@ { + } From a37b797dad8e78e6a37466e6a74f5ae9973eff2e Mon Sep 17 00:00:00 2001 From: maliming <6908465+maliming@users.noreply.github.com> Date: Mon, 10 Aug 2020 10:29:02 +0800 Subject: [PATCH 31/32] Update migrations for identity user IsExternal property. --- ....cs => 20200810022513_Initial.Designer.cs} | 6 +- ...s_Initial.cs => 20200810022513_Initial.cs} | 2 +- .../DemoAppDbContextModelSnapshot.cs | 2 +- ....cs => 20200810022447_Initial.Designer.cs} | 4 +- ...4_Initial.cs => 20200810022447_Initial.cs} | 0 .../BlobStoringHostDbContextModelSnapshot.cs | 2 +- ...0022522_IdentityUserIsExternal.Designer.cs | 1178 +++++++++++++++++ .../20200810022522_IdentityUserIsExternal.cs | 23 + .../BloggingTestAppDbContextModelSnapshot.cs | 8 +- ....cs => 20200810022553_Initial.Designer.cs} | 6 +- ...1_Initial.cs => 20200810022553_Initial.cs} | 0 ...verHostMigrationsDbContextModelSnapshot.cs | 4 +- ....cs => 20200810022644_Initial.Designer.cs} | 4 +- ...1_Initial.cs => 20200810022644_Initial.cs} | 0 .../UnifiedDbContextModelSnapshot.cs | 2 +- ....cs => 20200810022424_Initial.Designer.cs} | 10 +- ...5_Initial.cs => 20200810022424_Initial.cs} | 1 + .../VoloDocsDbContextModelSnapshot.cs | 8 +- ....cs => 20200810022238_Initial.Designer.cs} | 4 +- ...0_Initial.cs => 20200810022238_Initial.cs} | 0 ...ectNameMigrationsDbContextModelSnapshot.cs | 2 +- ....cs => 20200810022322_Initial.Designer.cs} | 10 +- ...9_Initial.cs => 20200810022322_Initial.cs} | 1 + ...verHostMigrationsDbContextModelSnapshot.cs | 8 +- ....cs => 20200810022405_Initial.Designer.cs} | 10 +- ...2_Initial.cs => 20200810022405_Initial.cs} | 1 + .../UnifiedDbContextModelSnapshot.cs | 8 +- 27 files changed, 1275 insertions(+), 29 deletions(-) rename modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/{20200624023633_BackgroundJobs_Initial.Designer.cs => 20200810022513_Initial.Designer.cs} (95%) rename modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/{20200624023633_BackgroundJobs_Initial.cs => 20200810022513_Initial.cs} (96%) rename modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/{20200624023744_Initial.Designer.cs => 20200810022447_Initial.Designer.cs} (97%) rename modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/{20200624023744_Initial.cs => 20200810022447_Initial.cs} (100%) create mode 100644 modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20200810022522_IdentityUserIsExternal.Designer.cs create mode 100644 modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20200810022522_IdentityUserIsExternal.cs rename modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/{20200624023331_Initial.Designer.cs => 20200810022553_Initial.Designer.cs} (99%) rename modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/{20200624023331_Initial.cs => 20200810022553_Initial.cs} (100%) rename modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/{20200729125121_Initial.Designer.cs => 20200810022644_Initial.Designer.cs} (99%) rename modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/{20200729125121_Initial.cs => 20200810022644_Initial.cs} (100%) rename modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/{20200722033325_Initial.Designer.cs => 20200810022424_Initial.Designer.cs} (99%) rename modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/{20200722033325_Initial.cs => 20200810022424_Initial.cs} (99%) rename templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/{20200806191520_Initial.Designer.cs => 20200810022238_Initial.Designer.cs} (99%) rename templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/{20200806191520_Initial.cs => 20200810022238_Initial.cs} (100%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/{20200710065039_Initial.Designer.cs => 20200810022322_Initial.Designer.cs} (99%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/{20200710065039_Initial.cs => 20200810022322_Initial.cs} (99%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/{20200710065052_Initial.Designer.cs => 20200810022405_Initial.Designer.cs} (99%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/{20200710065052_Initial.cs => 20200810022405_Initial.cs} (99%) diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200624023633_BackgroundJobs_Initial.Designer.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200810022513_Initial.Designer.cs similarity index 95% rename from modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200624023633_BackgroundJobs_Initial.Designer.cs rename to modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200810022513_Initial.Designer.cs index 40c0adcee7..cd91ca9fe9 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200624023633_BackgroundJobs_Initial.Designer.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200810022513_Initial.Designer.cs @@ -11,15 +11,15 @@ using Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.BackgroundJobs.DemoApp.Migrations { [DbContext(typeof(DemoAppDbContext))] - [Migration("20200624023633_BackgroundJobs_Initial")] - partial class BackgroundJobs_Initial + [Migration("20200810022513_Initial")] + partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200624023633_BackgroundJobs_Initial.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200810022513_Initial.cs similarity index 96% rename from modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200624023633_BackgroundJobs_Initial.cs rename to modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200810022513_Initial.cs index eebffa859a..99c4a11d89 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200624023633_BackgroundJobs_Initial.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/20200810022513_Initial.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace Volo.Abp.BackgroundJobs.DemoApp.Migrations { - public partial class BackgroundJobs_Initial : Migration + public partial class Initial : Migration { protected override void Up(MigrationBuilder migrationBuilder) { diff --git a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/DemoAppDbContextModelSnapshot.cs b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/DemoAppDbContextModelSnapshot.cs index fa77fd75ca..4a5df70449 100644 --- a/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/DemoAppDbContextModelSnapshot.cs +++ b/modules/background-jobs/app/Volo.Abp.BackgroundJobs.DemoApp/Migrations/DemoAppDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.BackgroundJobs.DemoApp.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200624023744_Initial.Designer.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200810022447_Initial.Designer.cs similarity index 97% rename from modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200624023744_Initial.Designer.cs rename to modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200810022447_Initial.Designer.cs index 5aa34b1eda..6d2051908a 100644 --- a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200624023744_Initial.Designer.cs +++ b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200810022447_Initial.Designer.cs @@ -11,7 +11,7 @@ using Volo.Abp.EntityFrameworkCore; namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.Migrations { [DbContext(typeof(BlobStoringHostDbContext))] - [Migration("20200624023744_Initial")] + [Migration("20200810022447_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -19,7 +19,7 @@ namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200624023744_Initial.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200810022447_Initial.cs similarity index 100% rename from modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200624023744_Initial.cs rename to modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/20200810022447_Initial.cs diff --git a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/BlobStoringHostDbContextModelSnapshot.cs b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/BlobStoringHostDbContextModelSnapshot.cs index 796c68b0ad..a32d6221d7 100644 --- a/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/BlobStoringHostDbContextModelSnapshot.cs +++ b/modules/blob-storing-database/host/BlobStoring.Database.Host.ConsoleApp/src/BlobStoring.Database.Host.ConsoleApp.ConsoleApp/Migrations/BlobStoringHostDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace BlobStoring.Database.Host.ConsoleApp.ConsoleApp.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20200810022522_IdentityUserIsExternal.Designer.cs b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20200810022522_IdentityUserIsExternal.Designer.cs new file mode 100644 index 0000000000..10ddf6bdf3 --- /dev/null +++ b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20200810022522_IdentityUserIsExternal.Designer.cs @@ -0,0 +1,1178 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; +using Volo.BloggingTestApp.EntityFrameworkCore; + +namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations +{ + [DbContext(typeof(BloggingTestAppDbContext))] + [Migration("20200810022522_IdentityUserIsExternal")] + partial class IdentityUserIsExternal + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("ProductVersion", "3.1.6") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("Description") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("Regex") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("RegexDescription") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDefault") + .HasColumnName("IsDefault") + .HasColumnType("bit"); + + b.Property("IsPublic") + .HasColumnName("IsPublic") + .HasColumnType("bit"); + + b.Property("IsStatic") + .HasColumnName("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedName") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(1024)") + .HasMaxLength(1024); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("ApplicationName") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("BrowserInfo") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ClientId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ClientIpAddress") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CorrelationId") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Identity") + .HasColumnType("nvarchar(96)") + .HasMaxLength(96); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnName("AccessFailedCount") + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasColumnName("Email") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnName("IsExternal") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime2"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("uniqueidentifier"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("LockoutEnabled") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasColumnName("Name") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("NormalizedEmail") + .IsRequired() + .HasColumnName("NormalizedEmail") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .IsRequired() + .HasColumnName("NormalizedUserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("PasswordHash") + .HasColumnName("PasswordHash") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasColumnType("nvarchar(16)") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("SecurityStamp") + .IsRequired() + .HasColumnName("SecurityStamp") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("Surname") + .HasColumnName("Surname") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnName("TwoFactorEnabled") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(1024)") + .HasMaxLength(1024); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasColumnType("nvarchar(196)") + .HasMaxLength(196); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("Name") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasColumnName("Code") + .HasColumnType("nvarchar(95)") + .HasMaxLength(95); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnName("DisplayName") + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime2"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("uniqueidentifier"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .IsRequired() + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ProviderName") + .IsRequired() + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(128)") + .HasMaxLength(128); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("ProviderName") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(2048)") + .HasMaxLength(2048); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Blogging.Blogs.Blog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnName("Description") + .HasColumnType("nvarchar(1024)") + .HasMaxLength(1024); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime2"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnName("Name") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("ShortName") + .IsRequired() + .HasColumnName("ShortName") + .HasColumnType("nvarchar(32)") + .HasMaxLength(32); + + b.HasKey("Id"); + + b.ToTable("BlgBlogs"); + }); + + modelBuilder.Entity("Volo.Blogging.Comments.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime2"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("uniqueidentifier"); + + b.Property("PostId") + .HasColumnName("PostId") + .HasColumnType("uniqueidentifier"); + + b.Property("RepliedCommentId") + .HasColumnName("RepliedCommentId") + .HasColumnType("uniqueidentifier"); + + b.Property("Text") + .IsRequired() + .HasColumnName("Text") + .HasColumnType("nvarchar(1024)") + .HasMaxLength(1024); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.HasIndex("RepliedCommentId"); + + b.ToTable("BlgComments"); + }); + + modelBuilder.Entity("Volo.Blogging.Posts.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnName("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("Content") + .HasColumnName("Content") + .HasColumnType("nvarchar(max)") + .HasMaxLength(1048576); + + b.Property("CoverImage") + .IsRequired() + .HasColumnName("CoverImage") + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnName("Description") + .HasColumnType("nvarchar(1000)") + .HasMaxLength(1000); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime2"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("uniqueidentifier"); + + b.Property("ReadCount") + .HasColumnType("int"); + + b.Property("Title") + .IsRequired() + .HasColumnName("Title") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("Url") + .IsRequired() + .HasColumnName("Url") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.HasKey("Id"); + + b.HasIndex("BlogId"); + + b.ToTable("BlgPosts"); + }); + + modelBuilder.Entity("Volo.Blogging.Posts.PostTag", b => + { + b.Property("PostId") + .HasColumnName("PostId") + .HasColumnType("uniqueidentifier"); + + b.Property("TagId") + .HasColumnName("TagId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("PostId", "TagId"); + + b.HasIndex("TagId"); + + b.ToTable("BlgPostTags"); + }); + + modelBuilder.Entity("Volo.Blogging.Tagging.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BlogId") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("CreationTime") + .HasColumnName("CreationTime") + .HasColumnType("datetime2"); + + b.Property("CreatorId") + .HasColumnName("CreatorId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeleterId") + .HasColumnName("DeleterId") + .HasColumnType("uniqueidentifier"); + + b.Property("DeletionTime") + .HasColumnName("DeletionTime") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnName("Description") + .HasColumnType("nvarchar(512)") + .HasMaxLength(512); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnName("IsDeleted") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("LastModificationTime") + .HasColumnName("LastModificationTime") + .HasColumnType("datetime2"); + + b.Property("LastModifierId") + .HasColumnName("LastModifierId") + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasColumnName("Name") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("UsageCount") + .HasColumnName("UsageCount") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("BlgTags"); + }); + + modelBuilder.Entity("Volo.Blogging.Users.BlogUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnName("ConcurrencyStamp") + .HasColumnType("nvarchar(40)") + .HasMaxLength(40); + + b.Property("Email") + .IsRequired() + .HasColumnName("Email") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("EmailConfirmed") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("ExtraProperties") + .HasColumnName("ExtraProperties") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnName("Name") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("PhoneNumber") + .HasColumnName("PhoneNumber") + .HasColumnType("nvarchar(16)") + .HasMaxLength(16); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnName("PhoneNumberConfirmed") + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("Surname") + .HasColumnName("Surname") + .HasColumnType("nvarchar(64)") + .HasMaxLength(64); + + b.Property("TenantId") + .HasColumnName("TenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .IsRequired() + .HasColumnName("UserName") + .HasColumnType("nvarchar(256)") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.ToTable("BlgUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Blogging.Comments.Comment", b => + { + b.HasOne("Volo.Blogging.Posts.Post", null) + .WithMany() + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Blogging.Comments.Comment", null) + .WithMany() + .HasForeignKey("RepliedCommentId"); + }); + + modelBuilder.Entity("Volo.Blogging.Posts.Post", b => + { + b.HasOne("Volo.Blogging.Blogs.Blog", null) + .WithMany() + .HasForeignKey("BlogId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Blogging.Posts.PostTag", b => + { + b.HasOne("Volo.Blogging.Posts.Post", null) + .WithMany("Tags") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Blogging.Tagging.Tag", null) + .WithMany() + .HasForeignKey("TagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20200810022522_IdentityUserIsExternal.cs b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20200810022522_IdentityUserIsExternal.cs new file mode 100644 index 0000000000..ee2e259b8a --- /dev/null +++ b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/20200810022522_IdentityUserIsExternal.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations +{ + public partial class IdentityUserIsExternal : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsExternal", + table: "AbpUsers", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsExternal", + table: "AbpUsers"); + } + } +} diff --git a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs index 24c52dfdd0..47647bb25e 100644 --- a/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs +++ b/modules/blogging/app/Volo.BloggingTestApp.EntityFrameworkCore/Migrations/BloggingTestAppDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -276,6 +276,12 @@ namespace Volo.BloggingTestApp.EntityFrameworkCore.Migrations .HasColumnType("bit") .HasDefaultValue(false); + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnName("IsExternal") + .HasColumnType("bit") + .HasDefaultValue(false); + b.Property("LastModificationTime") .HasColumnName("LastModificationTime") .HasColumnType("datetime2"); diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200624023331_Initial.Designer.cs b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200810022553_Initial.Designer.cs similarity index 99% rename from modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200624023331_Initial.Designer.cs rename to modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200810022553_Initial.Designer.cs index 406a3d3f68..aac1944355 100644 --- a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200624023331_Initial.Designer.cs +++ b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200810022553_Initial.Designer.cs @@ -5,13 +5,13 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Volo.CmsKit.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; +using Volo.CmsKit.EntityFrameworkCore; namespace Volo.CmsKit.Migrations { [DbContext(typeof(IdentityServerHostMigrationsDbContext))] - [Migration("20200624023331_Initial")] + [Migration("20200810022553_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -19,7 +19,7 @@ namespace Volo.CmsKit.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200624023331_Initial.cs b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200810022553_Initial.cs similarity index 100% rename from modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200624023331_Initial.cs rename to modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/20200810022553_Initial.cs diff --git a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs index 1218617479..b4249161b0 100644 --- a/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs +++ b/modules/cms-kit/host/Volo.CmsKit.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs @@ -4,8 +4,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Volo.CmsKit.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; +using Volo.CmsKit.EntityFrameworkCore; namespace Volo.CmsKit.Migrations { @@ -17,7 +17,7 @@ namespace Volo.CmsKit.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200729125121_Initial.Designer.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200810022644_Initial.Designer.cs similarity index 99% rename from modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200729125121_Initial.Designer.cs rename to modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200810022644_Initial.Designer.cs index 9d5d5e7c9d..a29b41671a 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200729125121_Initial.Designer.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200810022644_Initial.Designer.cs @@ -11,7 +11,7 @@ using Volo.CmsKit.EntityFrameworkCore; namespace Volo.CmsKit.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20200729125121_Initial")] + [Migration("20200810022644_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -19,7 +19,7 @@ namespace Volo.CmsKit.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200729125121_Initial.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200810022644_Initial.cs similarity index 100% rename from modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200729125121_Initial.cs rename to modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/20200810022644_Initial.cs diff --git a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index be32e92f05..cf98ee7acc 100644 --- a/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/modules/cms-kit/host/Volo.CmsKit.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace Volo.CmsKit.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200722033325_Initial.Designer.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200810022424_Initial.Designer.cs similarity index 99% rename from modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200722033325_Initial.Designer.cs rename to modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200810022424_Initial.Designer.cs index af038aaded..2cdcd59ea1 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200722033325_Initial.Designer.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200810022424_Initial.Designer.cs @@ -11,7 +11,7 @@ using VoloDocs.EntityFrameworkCore; namespace VoloDocs.EntityFrameworkCore.Migrations { [DbContext(typeof(VoloDocsDbContext))] - [Migration("20200722033325_Initial")] + [Migration("20200810022424_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -19,7 +19,7 @@ namespace VoloDocs.EntityFrameworkCore.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -278,6 +278,12 @@ namespace VoloDocs.EntityFrameworkCore.Migrations .HasColumnType("bit") .HasDefaultValue(false); + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnName("IsExternal") + .HasColumnType("bit") + .HasDefaultValue(false); + b.Property("LastModificationTime") .HasColumnName("LastModificationTime") .HasColumnType("datetime2"); diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200722033325_Initial.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200810022424_Initial.cs similarity index 99% rename from modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200722033325_Initial.cs rename to modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200810022424_Initial.cs index 29e68035f2..ce7877ad70 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200722033325_Initial.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20200810022424_Initial.cs @@ -155,6 +155,7 @@ namespace VoloDocs.EntityFrameworkCore.Migrations EmailConfirmed = table.Column(nullable: false, defaultValue: false), PasswordHash = table.Column(maxLength: 256, nullable: true), SecurityStamp = table.Column(maxLength: 256, nullable: false), + IsExternal = table.Column(nullable: false, defaultValue: false), PhoneNumber = table.Column(maxLength: 16, nullable: true), PhoneNumberConfirmed = table.Column(nullable: false, defaultValue: false), TwoFactorEnabled = table.Column(nullable: false, defaultValue: false), diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs index 085ce6399e..614e4eb25a 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace VoloDocs.EntityFrameworkCore.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -276,6 +276,12 @@ namespace VoloDocs.EntityFrameworkCore.Migrations .HasColumnType("bit") .HasDefaultValue(false); + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnName("IsExternal") + .HasColumnType("bit") + .HasDefaultValue(false); + b.Property("LastModificationTime") .HasColumnName("LastModificationTime") .HasColumnType("datetime2"); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200806191520_Initial.Designer.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200810022238_Initial.Designer.cs similarity index 99% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200806191520_Initial.Designer.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200810022238_Initial.Designer.cs index e5df7f6948..b4b16078a8 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200806191520_Initial.Designer.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200810022238_Initial.Designer.cs @@ -11,7 +11,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(MyProjectNameMigrationsDbContext))] - [Migration("20200806191520_Initial")] + [Migration("20200810022238_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200806191520_Initial.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200810022238_Initial.cs similarity index 100% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200806191520_Initial.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/20200810022238_Initial.cs diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs index 305502aa64..bd5937ba2c 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/Migrations/MyProjectNameMigrationsDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200810022322_Initial.Designer.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200810022322_Initial.Designer.cs index 00033c31b9..448351da20 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200810022322_Initial.Designer.cs @@ -11,7 +11,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(IdentityServerHostMigrationsDbContext))] - [Migration("20200710065039_Initial")] + [Migration("20200810022322_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -530,6 +530,12 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("bit") .HasDefaultValue(false); + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnName("IsExternal") + .HasColumnType("bit") + .HasDefaultValue(false); + b.Property("LastModificationTime") .HasColumnName("LastModificationTime") .HasColumnType("datetime2"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200810022322_Initial.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200810022322_Initial.cs index f80a5d9936..1ae2528b3a 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200710065039_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/20200810022322_Initial.cs @@ -208,6 +208,7 @@ namespace MyCompanyName.MyProjectName.Migrations EmailConfirmed = table.Column(nullable: false, defaultValue: false), PasswordHash = table.Column(maxLength: 256, nullable: true), SecurityStamp = table.Column(maxLength: 256, nullable: false), + IsExternal = table.Column(nullable: false, defaultValue: false), PhoneNumber = table.Column(maxLength: 16, nullable: true), PhoneNumberConfirmed = table.Column(nullable: false, defaultValue: false), TwoFactorEnabled = table.Column(nullable: false, defaultValue: false), diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs index 3129fab657..8cb7e3e88e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.IdentityServer/Migrations/IdentityServerHostMigrationsDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -528,6 +528,12 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("bit") .HasDefaultValue(false); + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnName("IsExternal") + .HasColumnType("bit") + .HasDefaultValue(false); + b.Property("LastModificationTime") .HasColumnName("LastModificationTime") .HasColumnType("datetime2"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200810022405_Initial.Designer.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200810022405_Initial.Designer.cs index 4afc02af46..9fa3f31af0 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200810022405_Initial.Designer.cs @@ -11,7 +11,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20200710065052_Initial")] + [Migration("20200810022405_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -19,7 +19,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -530,6 +530,12 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("bit") .HasDefaultValue(false); + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnName("IsExternal") + .HasColumnType("bit") + .HasDefaultValue(false); + b.Property("LastModificationTime") .HasColumnName("LastModificationTime") .HasColumnType("datetime2"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200810022405_Initial.cs similarity index 99% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200810022405_Initial.cs index a0d5e132a9..2e3df9b82a 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200710065052_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20200810022405_Initial.cs @@ -208,6 +208,7 @@ namespace MyCompanyName.MyProjectName.Migrations EmailConfirmed = table.Column(nullable: false, defaultValue: false), PasswordHash = table.Column(maxLength: 256, nullable: true), SecurityStamp = table.Column(maxLength: 256, nullable: false), + IsExternal = table.Column(nullable: false, defaultValue: false), PhoneNumber = table.Column(maxLength: 16, nullable: true), PhoneNumberConfirmed = table.Column(nullable: false, defaultValue: false), TwoFactorEnabled = table.Column(nullable: false, defaultValue: false), diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index 47b094f3c5..4d47e35a00 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -17,7 +17,7 @@ namespace MyCompanyName.MyProjectName.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("ProductVersion", "3.1.5") + .HasAnnotation("ProductVersion", "3.1.6") .HasAnnotation("Relational:MaxIdentifierLength", 128) .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); @@ -528,6 +528,12 @@ namespace MyCompanyName.MyProjectName.Migrations .HasColumnType("bit") .HasDefaultValue(false); + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnName("IsExternal") + .HasColumnType("bit") + .HasDefaultValue(false); + b.Property("LastModificationTime") .HasColumnName("LastModificationTime") .HasColumnType("datetime2"); From 36685d05a256f334ec33e69e6bea439587420d12 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 10 Aug 2020 14:24:19 +0800 Subject: [PATCH 32/32] Use CopyToAsync to copy the stream --- .../Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs index 142363d14e..204b1a6a1a 100644 --- a/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs +++ b/framework/src/Volo.Abp.BlobStoring.Minio/Volo/Abp/BlobStoring/Minio/MinioBlobProvider.cs @@ -72,11 +72,11 @@ namespace Volo.Abp.BlobStoring.Minio } var memoryStream = new MemoryStream(); - await client.GetObjectAsync(containerName, blobName, stream => + await client.GetObjectAsync(containerName, blobName, async stream => { if (stream != null) { - stream.CopyTo(memoryStream); + await stream.CopyToAsync(memoryStream); } else {