├── .gitattributes ├── .github └── workflows │ └── dotnetcore.yml ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── LICENSE ├── README.md ├── Zxw.Framework.NetCore.sln ├── Zxw.Framework.NetCore ├── Attributes │ ├── AjaxRequestOnlyAttribute.cs │ ├── FromDbContextFactoryAttribute.cs │ ├── IgnoreAttribute.cs │ └── ShardingTableAttribute.cs ├── Cache │ ├── DistributedCacheManager.cs │ ├── IDistributedCacheManager.cs │ ├── MemoryCacheManager.cs │ └── RedisCacheManager.cs ├── CodeGenerator │ ├── CodeFirst │ │ ├── CodeFirst.cs │ │ └── ICodeFirst.cs │ ├── CodeGenerator.cs │ ├── CodeGeneratorExtensions.cs │ └── DbFirst │ │ ├── DbFirst.cs │ │ └── IDbFirst.cs ├── CodeTemplate │ ├── ApiControllerTemplate.txt │ ├── ControllerTemplate.txt │ ├── IRepositoryTemplate.txt │ ├── IServiceTemplate.txt │ ├── ModelTemplate.txt │ ├── RepositoryTemplate.txt │ ├── ServiceTemplate.txt │ └── ViewModelTemplate.txt ├── Consts │ └── CommonConsts.cs ├── DbContextCore │ ├── BaseDbContext.cs │ ├── DbContextFactory.cs │ ├── InMemoryDbContext.cs │ ├── MySqlDbContext.cs │ ├── OracleDbContext.cs │ ├── PostgreSQLDbContext.cs │ ├── SQLiteDbContext.cs │ ├── ShardDbContextFactory.cs │ ├── SqlOperatorUtility.cs │ └── SqlServerDbContext.cs ├── DbLogProvider │ └── EFLoggerProvider.cs ├── Enums │ └── CommonEnums.cs ├── Extensions │ ├── CollectionExtension.cs │ ├── EntityFrameworkCoreExtensions.cs │ ├── ExpressionExtensions.cs │ ├── Extensions.Mapper.cs │ ├── GenericExtension.cs │ ├── HttpExtensions.cs │ ├── MvcExtension.cs │ ├── ObjectExtension.cs │ ├── ServiceExtension.cs │ ├── StringExtensions.cs │ └── TypeExtension.cs ├── Filters │ └── GlobalExceptionFilter.cs ├── Helpers │ ├── AsyncHelper.cs │ ├── CacheKey.cs │ ├── CommonHelper.cs │ ├── ConfigHelper.cs │ ├── EntityMapper.cs │ ├── HttpRequestHelper.cs │ ├── JsonConvertor.cs │ ├── Log4netHelper.cs │ ├── NPOIHelper.cs │ └── RuntimeHelper.cs ├── IDbContext │ ├── IDbContextCore.cs │ ├── IInMemoryDbContext.cs │ ├── IMongoDbContext.cs │ ├── IMySqlDbContext.cs │ ├── IOracleDbContext.cs │ ├── IPostgreSQLDbContext.cs │ ├── ISQLiteDbContext.cs │ ├── ISqlOperatorUtility.cs │ └── ISqlServerDbContext.cs ├── IoC │ ├── AspectCoreContainer.cs │ ├── AutofacContainer.cs │ ├── IScopedDependency.cs │ ├── ISingletonDependency.cs │ ├── ITransientDependency.cs │ ├── ServiceLifetimeDependencyInjectExtensions.cs │ └── ServiceLocator.cs ├── Middlewares │ └── ResponseTimeMiddleware.cs ├── Models │ ├── BaseModel.cs │ ├── DbColumnDataType.cs │ ├── DbTable.cs │ └── ExcutedResult.cs ├── Mvc │ └── BaseController.cs ├── Options │ ├── CodeGenerateOption.cs │ └── DbContextOption.cs ├── Repositories │ ├── BaseRepository.cs │ ├── IRepository.cs │ └── ServiceExtensions.cs ├── Services │ ├── BaseService.cs │ └── IServices.cs ├── Web │ ├── IWebContext.cs │ └── WebContext.cs └── Zxw.Framework.NetCore.csproj ├── Zxw.Framework.UnitTest ├── DbContextUnitTest.cs ├── TestModels │ └── SysMenu.cs ├── UnitTest1.cs └── Zxw.Framework.UnitTest.csproj ├── _config.yml └── azure-pipelines.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/workflows/dotnetcore.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Setup .NET Core 13 | uses: actions/setup-dotnet@v1 14 | with: 15 | dotnet-version: 6.0.100 16 | - name: Build with dotnet 17 | run: dotnet build --configuration Release 18 | - name: Pack 19 | run: dotnet pack "Zxw.Framework.NetCore/Zxw.Framework.NetCore.csproj" --configuration Release -p:PackageVersion=6.0.0 --output nupkgs 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | /Zxw.Framework 263 | /Zxw.Framework.Sample 264 | /Zxw.Framework.Sample.IRepositories 265 | /Zxw.Framework.Sample.IServices 266 | /Zxw.Framework.Sample.Models 267 | /Zxw.Framework.Sample.Repositories 268 | /Zxw.Framework.Sample.Services 269 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (web)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/Zxw.Framework.Website/bin/Debug/netcoreapp2.0/Zxw.Framework.Website.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/Zxw.Framework.Website", 16 | "stopAtEntry": false, 17 | "internalConsoleOptions": "openOnSessionStart", 18 | "launchBrowser": { 19 | "enabled": true, 20 | "args": "${auto-detect-url}", 21 | "windows": { 22 | "command": "cmd.exe", 23 | "args": "/C start ${auto-detect-url}" 24 | }, 25 | "osx": { 26 | "command": "open" 27 | }, 28 | "linux": { 29 | "command": "xdg-open" 30 | } 31 | }, 32 | "env": { 33 | "ASPNETCORE_ENVIRONMENT": "Development" 34 | }, 35 | "sourceFileMap": { 36 | "/Views": "${workspaceFolder}/Views" 37 | } 38 | }, 39 | { 40 | "name": ".NET Core Attach", 41 | "type": "coreclr", 42 | "request": "attach", 43 | "processId": "${command:pickProcess}" 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "taskName": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/Zxw.Framework.Website/Zxw.Framework.Website.csproj" 11 | ], 12 | "problemMatcher": "$msCompile" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 旺仔 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zxw.Framework.NetCore 2 | [![Build Status](https://dev.azure.com/v-xiaze0473/v-xiaze/_apis/build/status/VictorTzeng.Zxw.Framework.NetCore?branchName=master)](https://dev.azure.com/v-xiaze0473/v-xiaze/_build/latest?definitionId=1&branchName=master) 3 | 4 | 基于EF Core的Code First模式的DotNetCore快速开发框架 5 | 6 | **Nuget [最新版本:6.1.0]** 7 | 8 | [Zxw.Framework.NetCore](https://www.nuget.org/packages/Zxw.Framework.NetCore/6.1.0) 9 | * Install-Package Zxw.Framework.NetCore -Version 6.1.0 10 | * dotnet add package Zxw.Framework.NetCore --version 6.1.0 11 | 12 | **开发环境** 13 | * VS2019 / VS Code 14 | * .net core 3.1.100 15 | 16 | **支持的数据库** 17 | * SQL Server 18 | * MySQL 19 | * Sqlite 20 | * InMemory 21 | * PostgreSQL 22 | * Oracle 23 | * MongoDB (已移除) 24 | 25 | **日志组件** 26 | * log4net 27 | 28 | **DI组件** 29 | * Autofac 30 | * [Aspectcore.Injector](https://github.com/dotnetcore/AspectCore-Framework/blob/master/docs/injector.md) 31 | 32 | **AOP缓存组件使用** 33 | 34 | 本项目采用的AOP中间件 :[AspectCore.Extensions.Cache](https://github.com/VictorTzeng/AspectCore.Extensions.Cache) 35 | 36 | # 示例 37 | * [Zxw.Framework.NetCore.Demo](https://github.com/VictorTzeng/Zxw.Framework.NetCore.Demo) 38 | 39 | 40 | # .net framework版本地址 41 | * [Zxw.Framework.Nfx](https://github.com/VictorTzeng/Zxw.Framework.Nfx) 42 | 43 | # 项目说明 44 | * 请参考我的博客:[http://www.cnblogs.com/zengxw/p/7673952.html](http://www.cnblogs.com/zengxw/p/7673952.html) 45 | 46 | # 更新日志 47 | 48 | **2022/11/20** 49 | * 1.兼容.net7.0, 50 | * 2.移除对MongoDB的支持 51 | * 3.HttpRequestHelper标识为已过时,请用HttpClient 52 | 53 | **2019/12/17** 54 | * 1. 添加框架同一入口扩展方法 [AddCoreX](https://github.com/VictorTzeng/Zxw.Framework.NetCore/blob/66ce81a3ffa3eb9379631ba11a3fd36c4c369e60/Zxw.Framework.NetCore/Extensions/ServiceExtension.cs#L419) 55 | ``` 56 | services.AddCoreX(config=> { }) 57 | ``` 58 | 59 | * 2. AddCoreX方法里面默认开启注入实现了ISingletonDependency、IScopedDependency、ITransientDependency三种不同生命周期的类,以及AddHttpContextAccessor和AddDataProtection。如需要自动注入,只需要按需实现ISingletonDependency、IScopedDependency、ITransientDependency这三种生命周期接口即可。 60 | 61 | * 3. 添加会话上下文 [WebContext](https://github.com/VictorTzeng/Zxw.Framework.NetCore/blob/master/Zxw.Framework.NetCore/Web/WebContext.cs) 62 | 63 | * 4. 升级 [AspectCore](https://github.com/dotnetcore/AspectCore-Framework) 至 2.0.0 64 | 65 | * 5. 示例 [Zxw.Framework.NetCore.Demo](https://github.com/VictorTzeng/Zxw.Framework.NetCore.Demo) 已同步更新。 66 | 67 | **2019/09/16** 68 | * 1.更换Oracle for efcore驱动,使用Oracle官方驱动 69 | 70 | **2019/09/15** 71 | * 1.重构AOP缓存,统一用CachedAttribute 72 | 73 | **2019/08/11** 74 | * 1.重构代码生成器,分CodeFirst和DbFirst 75 | 76 | a.启用代码生成器 77 | ``` 78 | 79 | //启用代码生成器 80 | services.UseCodeGenerator(new CodeGeneratorOption()); 81 | 82 | ``` 83 | 84 | b.使用代码生成器 85 | 86 | ``` 87 | 88 | //CodeFirst---根据model生成其他各层的代码 89 | dbContext.CodeFirst().GenerateAll(ifExsitedCovered:true); 90 | 91 | //DbFirst---根据现有数据表生成各层代码 92 | dbCOntext.DbFirst().GenerateAll(ifExsitedCovered:true); 93 | 94 | ``` 95 | * 2.添加对APIController的代码生成 96 | 97 | **2019/04/25** 98 | * 1.修改缓存拦截器默认key格式为:{namespace}{class}{method}{参数值hashcode} 99 | * 2.缓存拦截器添加对Task<>类型的支持 100 | 101 | 102 | **2019/04/18** 103 | * 1.删除触发器功能... 104 | * 2.实现多数据库上下文。用法: 105 | 106 | ``` 107 | //注入数据库上下文 108 | services.AddDbContextFactory(factory => 109 | { 110 | factory.AddDbContext("db1", new DbContextOption(){ConnectionString = "User ID=postgres;Password=123456;Host=localhost;Port=5432;Database=ZxwPgDemo;Pooling=true;" }); 111 | factory.AddDbContext("db2", new DbContextOption() { ConnectionString = "" }); 112 | factory.AddDbContext("db3", new DbContextOption() { ConnectionString = "" }); 113 | }); 114 | 115 | 116 | //获取 117 | public class TestController 118 | { 119 | public IDbContextCore DbContext1 { get; set; } 120 | public IDbContextCore DbContext2 { get; set; } 121 | public IDbContextCore DbContext3 { get; set; } 122 | 123 | public TestController(DbContextFactory factory) 124 | { 125 | DbContext1 = factory.GetDbContext("db1"); 126 | DbContext2 = factory.GetDbContext("db2"); 127 | DbContext3 = factory.GetDbContext("db3"); 128 | } 129 | 130 | public void Run() 131 | { 132 | var db = DbContext1.GetDatabase(); 133 | Console.WriteLine(); 134 | } 135 | } 136 | ``` 137 | 138 | * 3.多数据库上下文支持属性注入,用法如下:(具体请参考单元测试) 139 | ``` 140 | public class TestRepository: BaseRepository, IMongoRepository 141 | { 142 | [FromDbContextFactory("db1")] 143 | public IDbContextCore DbContext1 { get; set; } 144 | [FromDbContextFactory("db2")] 145 | public IDbContextCore DbContext2 { get; set; } 146 | [FromDbContextFactory("db3")] 147 | public IDbContextCore DbContext3 { get; set; } 148 | 149 | 150 | 151 | public void Run() 152 | { 153 | Console.WriteLine("Over!"); 154 | } 155 | 156 | public TestRepository(IDbContextCore dbContext) : base(dbContext) 157 | { 158 | } 159 | } 160 | ``` 161 | 162 | **2018/09/24** 163 | * 1.实现Oracle for EfCore,引用第三方驱动[Citms.EntityFrameworkCore.Oracle](https://github.com/CrazyJson/Citms.EntityFrameworkCore.Oracle) 164 | * 2.实现MongoDB for EfCore,引用第三方驱动[Blueshift.EntityFrameworkCore.MongoDB](https://github.com/BlueshiftSoftware/EntityFrameworkCore) 165 | 166 | **2018/08/26** 167 | * 1.添加自定义视图分页查询,数据库分页,目前只支持sqlserver 168 | * 2.update packages 169 | 170 | **2018/07/06 合并dev分支到master** 171 | * 1.添加EFCore直接返回[DataTable](https://github.com/VictorTzeng/Zxw.Framework.NetCore/blob/d99b321006ad7ee12883e92742d3ef1fe44968f7/Zxw.Framework.NetCore/Extensions/EntityFrameworkCoreExtensions.cs#L20)功能 172 | * 2.DBFirst功能,目前仅支持SQL Server、MySQL、NpgSQL三种数据库。根据已存在的数据表直接生成实体代码,详见[CodeGenerator](https://github.com/VictorTzeng/Zxw.Framework.NetCore/blob/b07589d550a9f757b8da75e4fc685b917be29f34/Zxw.Framework.NetCore/CodeGenerator/CodeGenerator.cs#L197) 173 | * 3.添加单元测试项目,并完成对以上两点新功能的测试 174 | * 4.引入IOC容器[Aspectcore.Injector](https://github.com/dotnetcore/AspectCore-Framework/blob/master/docs/injector.md),详见[AspectCoreContainer.cs](https://github.com/VictorTzeng/Zxw.Framework.NetCore/blob/master/Zxw.Framework.NetCore/IoC/AspectCoreContainer.cs) 175 | 176 | # 开源协议 177 | * 本开源项目遵守[MIT](https://github.com/VictorTzeng/Zxw.Framework.NetCore/blob/master/LICENSE)开源协议,请保留原作者出处。 178 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27004.2002 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Zxw.Framework.NetCore", "Zxw.Framework.NetCore\Zxw.Framework.NetCore.csproj", "{3CA31344-BC8F-47A2-B23F-A6CDB3DEC255}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Zxw.Framework.UnitTest", "Zxw.Framework.UnitTest\Zxw.Framework.UnitTest.csproj", "{0E7B2942-A74D-4297-B2A8-7F7C5955C476}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {3CA31344-BC8F-47A2-B23F-A6CDB3DEC255}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {3CA31344-BC8F-47A2-B23F-A6CDB3DEC255}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {3CA31344-BC8F-47A2-B23F-A6CDB3DEC255}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {3CA31344-BC8F-47A2-B23F-A6CDB3DEC255}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {0E7B2942-A74D-4297-B2A8-7F7C5955C476}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {0E7B2942-A74D-4297-B2A8-7F7C5955C476}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {0E7B2942-A74D-4297-B2A8-7F7C5955C476}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {0E7B2942-A74D-4297-B2A8-7F7C5955C476}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {E96BCD9A-C6E5-4F84-ABB0-1203F62A4470} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Attributes/AjaxRequestOnlyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.Filters; 4 | using Zxw.Framework.NetCore.Extensions; 5 | using Zxw.Framework.NetCore.Helpers; 6 | 7 | namespace Zxw.Framework.NetCore.Attributes 8 | { 9 | public class AjaxRequestOnlyAttribute : ActionFilterAttribute, IExceptionFilter 10 | { 11 | public override void OnActionExecuting(ActionExecutingContext context) 12 | { 13 | if (!context.HttpContext.Request.IsAjaxRequest()) 14 | { 15 | context.Result = new JsonResult(new{ success =false, msg = "This method only allows Ajax requests."}); 16 | context.HttpContext.Response.StatusCode = HttpStatusCode.Forbidden.GetHashCode(); 17 | } 18 | base.OnActionExecuting(context); 19 | } 20 | 21 | public void OnException(ExceptionContext context) 22 | { 23 | var type = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType; 24 | Log4NetHelper.WriteError(type, context.Exception); 25 | 26 | context.Result = new JsonResult(new{ success =false, msg = context.Exception.Message}); 27 | context.HttpContext.Response.StatusCode = HttpStatusCode.InternalServerError.GetHashCode(); 28 | context.ExceptionHandled = true; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Attributes/FromDbContextFactoryAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using System.Threading.Tasks; 5 | using AspectCore.DynamicProxy; 6 | using Zxw.Framework.NetCore.Extensions; 7 | 8 | namespace Zxw.Framework.NetCore.Attributes 9 | { 10 | [AttributeUsage(AttributeTargets.Property|AttributeTargets.Field|AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] 11 | public class FromDbContextFactoryAttribute: Attribute 12 | { 13 | public string DbContextTagName { get; set; } 14 | 15 | public FromDbContextFactoryAttribute(string tagName) 16 | { 17 | DbContextTagName = tagName; 18 | } 19 | } 20 | 21 | 22 | public class FromDbContextFactoryInterceptor : AbstractInterceptorAttribute 23 | { 24 | public override Task Invoke(AspectContext context, AspectDelegate next) 25 | { 26 | var impType = context.Implementation.GetType(); 27 | var properties = impType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) 28 | .Where(p => p.IsDefined(typeof(FromDbContextFactoryAttribute))).ToList(); 29 | if (properties.Any()) 30 | { 31 | foreach (var property in properties) 32 | { 33 | var attribute = property.GetCustomAttribute(); 34 | var dbContext = context.ServiceProvider.GetDbContext(attribute.DbContextTagName, property.PropertyType); 35 | property.SetValue(context.Implementation, dbContext); 36 | } 37 | } 38 | return context.Invoke(next); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Attributes/IgnoreAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc.Filters; 3 | 4 | namespace Zxw.Framework.NetCore.Attributes 5 | { 6 | public class IgnoreAttribute:Attribute, IFilterMetadata 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Attributes/ShardingTableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Schema; 2 | 3 | namespace Zxw.Framework.NetCore.Attributes 4 | { 5 | public class ShardingTableAttribute:TableAttribute 6 | { 7 | /// 8 | /// 9 | /// 10 | public string Splitter { get; set; } = "_"; 11 | /// 12 | /// 分表后缀格式。默认值:_yyyyMMdd 13 | /// 14 | public string Suffix { get; set; } = "yyyyMMdd"; 15 | public ShardingTableAttribute(string name) : base(name) 16 | { 17 | this.Suffix = "yyyyMMdd"; 18 | this.Splitter = "_"; 19 | } 20 | 21 | public ShardingTableAttribute(string name, string splitter = "_", string suffix = "yyyyMMdd") : base(name) 22 | { 23 | this.Suffix = suffix; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Cache/DistributedCacheManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Threading.Tasks; 4 | using Microsoft.Extensions.Caching.Distributed; 5 | using Zxw.Framework.NetCore.Extensions; 6 | 7 | namespace Zxw.Framework.NetCore.Cache 8 | { 9 | public class DistributedCacheManager:IDistributedCacheManager 10 | { 11 | private IDistributedCache _cache; 12 | public DistributedCacheManager(IDistributedCache cache) 13 | { 14 | _cache = cache; 15 | } 16 | 17 | public void Set(string key, object value) 18 | { 19 | if (value == null) return; 20 | _cache.Set(key, value.ToBytes()); 21 | } 22 | 23 | public async Task SetAsync(string key, object value) 24 | { 25 | if (value == null) return; 26 | await _cache.SetAsync(key, value.ToBytes()); 27 | } 28 | public void Set(string key, object value, int expiredSeconds) 29 | { 30 | if (value == null) return; 31 | _cache.Set(key, value.ToBytes(), new DistributedCacheEntryOptions() 32 | { 33 | AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(expiredSeconds) 34 | }); 35 | } 36 | 37 | public async Task SetAsync(string key, object value, int expiredSeconds) 38 | { 39 | if (value == null) return; 40 | await _cache.SetAsync(key, value.ToBytes(), new DistributedCacheEntryOptions() 41 | { 42 | AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(expiredSeconds) 43 | }); 44 | } 45 | 46 | public object Get(string key) 47 | { 48 | var data = _cache.Get(key); 49 | return data?.ToObject(); 50 | } 51 | 52 | public async Task GetAsync(string key) 53 | { 54 | var data = await _cache.GetAsync(key); 55 | return data?.ToObject(); 56 | } 57 | 58 | public object Get(string key, Type type) 59 | { 60 | return Convert.ChangeType(Get(key), type); 61 | } 62 | 63 | public async Task GetAsync(string key, Type type) 64 | { 65 | return Convert.ChangeType(await GetAsync(key), type); 66 | } 67 | 68 | public T Get(string key) 69 | { 70 | var data = _cache.Get(key); 71 | return (T) data?.ToObject(); 72 | } 73 | 74 | public async Task GetAsync(string key) 75 | { 76 | var data = await _cache.GetAsync(key); 77 | return (T) data?.ToObject(); 78 | } 79 | 80 | public object Get(string key, Func func) 81 | { 82 | var result = Get(key); 83 | if (result == null) 84 | { 85 | result = func.Invoke(); 86 | Set(key, result); 87 | } 88 | 89 | return result; 90 | } 91 | public async Task GetAsync(string key, Func func) 92 | { 93 | var result = await GetAsync(key); 94 | if (result == null) 95 | { 96 | result = func.Invoke(); 97 | await SetAsync(key, result); 98 | } 99 | 100 | return result; 101 | } 102 | public T Get(string key, Func func) 103 | { 104 | var result = Get(key); 105 | if (result == null) 106 | { 107 | result = func.Invoke(); 108 | Set(key, result); 109 | } 110 | 111 | return result; 112 | } 113 | public async Task GetAsync(string key, Func func) 114 | { 115 | var result = await GetAsync(key); 116 | if (result == null) 117 | { 118 | result = func.Invoke(); 119 | await SetAsync(key, result); 120 | } 121 | 122 | return result; 123 | } 124 | 125 | public object Get(string key, Func func, int expiredSeconds) 126 | { 127 | var result = Get(key); 128 | if (result == null) 129 | { 130 | result = func.Invoke(); 131 | Set(key, result, expiredSeconds); 132 | } 133 | 134 | return result; 135 | } 136 | public async Task GetAsync(string key, Func func, int expiredSeconds) 137 | { 138 | var result = await GetAsync(key); 139 | if (result == null) 140 | { 141 | result = func.Invoke(); 142 | await SetAsync(key, result, expiredSeconds); 143 | } 144 | 145 | return result; 146 | } 147 | public T Get(string key, Func func, int expiredSeconds) 148 | { 149 | var result = Get(key); 150 | if (result == null) 151 | { 152 | result = func.Invoke(); 153 | Set(key, result, expiredSeconds); 154 | } 155 | 156 | return result; 157 | } 158 | public async Task GetAsync(string key, Func func, int expiredSeconds) 159 | { 160 | var result = await GetAsync(key); 161 | if (result == null) 162 | { 163 | if (func.Method.IsDefined(typeof(AsyncStateMachineAttribute), false)) 164 | { 165 | dynamic invoked = func.Invoke(); 166 | if (invoked is Task task) 167 | { 168 | result = (T)task.Result; 169 | } 170 | } 171 | else 172 | { 173 | result = func.Invoke(); 174 | } 175 | await SetAsync(key, result, expiredSeconds); 176 | } 177 | 178 | return result; 179 | } 180 | 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Cache/IDistributedCacheManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Zxw.Framework.NetCore.Cache 5 | { 6 | public interface IDistributedCacheManager 7 | { 8 | void Set(string key, object value); 9 | Task SetAsync(string key, object value); 10 | void Set(string key, object value, int expiredSeconds); 11 | Task SetAsync(string key, object value, int expiredSeconds); 12 | object Get(string key); 13 | Task GetAsync(string key); 14 | object Get(string key, Type type); 15 | Task GetAsync(string key, Type type); 16 | T Get(string key); 17 | Task GetAsync(string key); 18 | object Get(string key, Func func); 19 | Task GetAsync(string key, Func func); 20 | T Get(string key, Func func); 21 | Task GetAsync(string key, Func func); 22 | object Get(string key, Func func, int expiredSeconds); 23 | Task GetAsync(string key, Func func, int expiredSeconds); 24 | T Get(string key, Func func, int expiredSeconds); 25 | Task GetAsync(string key, Func func, int expiredSeconds); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Cache/MemoryCacheManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Caching.Memory; 2 | using Zxw.Framework.NetCore.IoC; 3 | 4 | namespace Zxw.Framework.NetCore.Cache 5 | { 6 | public class MemoryCacheManager 7 | { 8 | public static IMemoryCache GetInstance() => ServiceLocator.Resolve(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Cache/RedisCacheManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Caching.Distributed; 4 | using Zxw.Framework.NetCore.Helpers; 5 | using Zxw.Framework.NetCore.IoC; 6 | 7 | namespace Zxw.Framework.NetCore.Cache 8 | { 9 | public class RedisCacheManager 10 | { 11 | private static IDistributedCache Instance => ServiceLocator.Resolve(); 12 | 13 | public static string Get(string key) 14 | { 15 | if (RedisHelper.Exists(key)) 16 | { 17 | return RedisHelper.Get(key); 18 | } 19 | 20 | return null; 21 | } 22 | 23 | public static async Task GetAsync(string key) 24 | { 25 | if (await RedisHelper.ExistsAsync(key)) 26 | { 27 | var content = await RedisHelper.GetAsync(key); 28 | return content; 29 | } 30 | 31 | return null; 32 | } 33 | 34 | public static T Get(string key) 35 | { 36 | var value = Get(key); 37 | if (!string.IsNullOrEmpty(value)) 38 | return JsonConvertor.Deserialize(value); 39 | return default(T); 40 | } 41 | 42 | public static async Task GetAsync(string key) 43 | { 44 | var value = await GetAsync(key); 45 | if (!string.IsNullOrEmpty(value)) 46 | { 47 | return JsonConvertor.Deserialize(value); 48 | } 49 | 50 | return default(T); 51 | } 52 | 53 | public static void Set(string key, object data, int expiredSeconds) 54 | { 55 | RedisHelper.Set(key, JsonConvertor.Serialize(data), expiredSeconds); 56 | } 57 | 58 | public static async Task SetAsync(string key, object data, int expiredSeconds) 59 | { 60 | return await RedisHelper.SetAsync(key, JsonConvertor.Serialize(data), expiredSeconds); 61 | } 62 | 63 | 64 | public static void Remove(string key) => Instance.Remove(key); 65 | 66 | public static async Task RemoveAsync(string key) => await Instance.RemoveAsync(key); 67 | 68 | public static void Refresh(string key) => Instance.Refresh(key); 69 | 70 | public static async Task RefreshAsync(string key) => await Instance.RefreshAsync(key); 71 | 72 | public static void Clear() 73 | { 74 | throw new NotImplementedException(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeGenerator/CodeFirst/CodeFirst.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Options; 3 | using Zxw.Framework.NetCore.Models; 4 | using Zxw.Framework.NetCore.Options; 5 | 6 | namespace Zxw.Framework.NetCore.CodeGenerator.CodeFirst 7 | { 8 | internal sealed class CodeFirst:ICodeFirst 9 | { 10 | private CodeGenerator Instance { get; set; } 11 | public CodeFirst(IOptions option) 12 | { 13 | if (option == null) throw new ArgumentNullException(nameof(option)); 14 | Instance = new CodeGenerator(option.Value); 15 | } 16 | 17 | public void GenerateAll(bool ifExistCovered = false) 18 | { 19 | Instance.Generate(ifExistCovered); 20 | } 21 | 22 | public ICodeFirst GenerateSingle(bool ifExistCovered = false) where T : IBaseModel 23 | { 24 | Instance.GenerateSingle(ifExistCovered); 25 | return this; 26 | } 27 | 28 | public ICodeFirst GenerateIRepository(bool ifExistCovered = false) where T : IBaseModel 29 | { 30 | Instance.GenerateIRepository(ifExistCovered); 31 | return this; 32 | } 33 | 34 | public ICodeFirst GenerateRepository(bool ifExistCovered = false) where T : IBaseModel 35 | { 36 | Instance.GenerateRepository(ifExistCovered); 37 | return this; 38 | } 39 | 40 | public ICodeFirst GenerateIService(bool ifExistCovered = false) where T : IBaseModel 41 | { 42 | Instance.GenerateIService(ifExistCovered); 43 | return this; 44 | } 45 | 46 | public ICodeFirst GenerateService(bool ifExistCovered = false) where T : IBaseModel 47 | { 48 | Instance.GenerateService(ifExistCovered); 49 | return this; 50 | } 51 | 52 | public ICodeFirst GenerateController(bool ifExistCovered = false) where T : IBaseModel 53 | { 54 | Instance.GenerateController(ifExistCovered); 55 | return this; 56 | } 57 | 58 | public ICodeFirst GenerateApiController(bool ifExistCovered = false) where T : IBaseModel 59 | { 60 | Instance.GenerateApiController(ifExistCovered); 61 | return this; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeGenerator/CodeFirst/ICodeFirst.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Zxw.Framework.NetCore.IDbContext; 3 | using Zxw.Framework.NetCore.IoC; 4 | using Zxw.Framework.NetCore.Models; 5 | 6 | namespace Zxw.Framework.NetCore.CodeGenerator.CodeFirst 7 | { 8 | public interface ICodeFirst 9 | { 10 | void GenerateAll(bool ifExistCovered = false); 11 | ICodeFirst GenerateSingle(bool ifExistCovered = false) where T : IBaseModel; 12 | ICodeFirst GenerateIRepository(bool ifExistCovered = false) where T : IBaseModel; 13 | ICodeFirst GenerateRepository(bool ifExistCovered = false) where T : IBaseModel; 14 | ICodeFirst GenerateIService(bool ifExistCovered = false) where T : IBaseModel; 15 | ICodeFirst GenerateService(bool ifExistCovered = false) where T : IBaseModel; 16 | ICodeFirst GenerateController(bool ifExistCovered = false) where T : IBaseModel; 17 | ICodeFirst GenerateApiController(bool ifExistCovered = false) where T : IBaseModel; 18 | } 19 | 20 | public static class CodeFirstExtensions 21 | { 22 | public static ICodeFirst CodeFirst(this IDbContextCore dbContext) 23 | { 24 | var codeFirst = ServiceLocator.Resolve(); 25 | if (codeFirst == null) 26 | throw new Exception("请先在Startup.cs文件的ConfigureServices方法中调用UseCodeGenerator方法以注册。"); 27 | return codeFirst; 28 | } 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeGenerator/CodeGeneratorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Zxw.Framework.NetCore.CodeGenerator.CodeFirst; 5 | using Zxw.Framework.NetCore.CodeGenerator.DbFirst; 6 | using Zxw.Framework.NetCore.IDbContext; 7 | using Zxw.Framework.NetCore.IoC; 8 | using Zxw.Framework.NetCore.Models; 9 | using Zxw.Framework.NetCore.Options; 10 | 11 | namespace Zxw.Framework.NetCore.CodeGenerator 12 | { 13 | public static class CodeGeneratorExtenstions 14 | { 15 | public static void ToGenerateViewModelFile(this DataTable dt, string className) 16 | { 17 | var dbContext = ServiceLocator.Resolve(); 18 | dbContext.DbFirst().GenerateViewModel(dt, className); 19 | } 20 | 21 | public static void ToGenerateViewModelFile(this DataSet ds) 22 | { 23 | if (ds == null) throw new ArgumentNullException(nameof(ds)); 24 | foreach (DataTable table in ds.Tables) 25 | { 26 | table.ToGenerateViewModelFile(table.TableName); 27 | } 28 | } 29 | 30 | public static void GenerateAllCodesFromDatabase(this IDbContextCore dbContext, bool ifExistCovered = false, 31 | Func selector = null) 32 | { 33 | dbContext.DbFirst().Generate(selector, ifExistCovered); 34 | } 35 | 36 | public static void UseCodeGenerator(this IServiceCollection services, CodeGenerateOption option) 37 | { 38 | if (option == null) 39 | throw new ArgumentNullException(nameof(option)); 40 | services.Configure(config => 41 | { 42 | config.ControllersNamespace = option.ControllersNamespace; 43 | config.IRepositoriesNamespace = option.IRepositoriesNamespace; 44 | config.IServicesNamespace = option.IServicesNamespace; 45 | config.ModelsNamespace = option.ModelsNamespace; 46 | config.OutputPath = option.OutputPath; 47 | config.RepositoriesNamespace = option.RepositoriesNamespace; 48 | config.ServicesNamespace = option.ServicesNamespace; 49 | config.ViewModelsNamespace = option.ViewModelsNamespace; 50 | config.IsPascalCase = option.IsPascalCase; 51 | }); 52 | services.AddSingleton(); 53 | services.AddSingleton(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeGenerator/DbFirst/DbFirst.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Linq; 5 | using Microsoft.Extensions.Options; 6 | using Zxw.Framework.NetCore.Extensions; 7 | using Zxw.Framework.NetCore.IDbContext; 8 | using Zxw.Framework.NetCore.Models; 9 | using Zxw.Framework.NetCore.Options; 10 | 11 | namespace Zxw.Framework.NetCore.CodeGenerator.DbFirst 12 | { 13 | internal sealed class DbFirst : IDbFirst 14 | { 15 | private CodeGenerator Instance { get; set; } 16 | 17 | private IDbContextCore _dbContext; 18 | 19 | private List AllTables => _dbContext.GetCurrentDatabaseTableList().ToList(); 20 | 21 | public DbFirst(IDbContextCore dbContext, IOptions option) 22 | { 23 | _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); 24 | if (option == null) throw new ArgumentNullException(nameof(option)); 25 | Instance = new CodeGenerator(option.Value); 26 | } 27 | 28 | public void GenerateAll(bool ifExistCovered = false) 29 | { 30 | Instance.Generate(AllTables,ifExistCovered); 31 | } 32 | 33 | public IDbFirst Generate(Func selector, bool ifExistCovered = false) 34 | { 35 | if (selector == null) 36 | selector = m => true; 37 | Instance.Generate(AllTables.Where(selector).ToList(), ifExistCovered); 38 | return this; 39 | } 40 | 41 | public IDbFirst GenerateEntity(Func selector, bool ifExistCovered = false) 42 | { 43 | var tables = AllTables.Where(selector).ToList(); 44 | foreach (var table in tables) 45 | { 46 | Instance.GenerateEntity(table, ifExistCovered); 47 | } 48 | return this; 49 | } 50 | 51 | public IDbFirst GenerateSingle(Func selector, bool ifExistCovered = false) 52 | { 53 | GenerateEntity(selector, ifExistCovered); 54 | GenerateIRepository(selector, ifExistCovered); 55 | GenerateRepository(selector, ifExistCovered); 56 | GenerateIService(selector, ifExistCovered); 57 | GenerateService(selector, ifExistCovered); 58 | GenerateController(selector, ifExistCovered); 59 | GenerateApiController(selector, ifExistCovered); 60 | 61 | return this; 62 | } 63 | 64 | public IDbFirst GenerateIRepository(Func selector, bool ifExistCovered = false) 65 | { 66 | var tables = AllTables.Where(selector).ToList(); 67 | foreach (var table in tables) 68 | { 69 | if (table.Columns.Any(c => c.IsPrimaryKey)) 70 | { 71 | var pkTypeName = table.Columns.First(m => m.IsPrimaryKey).CSharpType; 72 | Instance.GenerateIRepository(table.TableName, pkTypeName, ifExistCovered); 73 | } 74 | } 75 | 76 | return this; 77 | } 78 | 79 | public IDbFirst GenerateRepository(Func selector, bool ifExistCovered = false) 80 | { 81 | var tables = AllTables.Where(selector).ToList(); 82 | foreach (var table in tables) 83 | { 84 | if (table.Columns.Any(c => c.IsPrimaryKey)) 85 | { 86 | var pkTypeName = table.Columns.First(m => m.IsPrimaryKey).CSharpType; 87 | Instance.GenerateRepository(table.TableName, pkTypeName, ifExistCovered); 88 | } 89 | } 90 | 91 | return this; 92 | } 93 | 94 | public IDbFirst GenerateIService(Func selector, bool ifExistCovered = false) 95 | { 96 | var tables = AllTables.Where(selector).ToList(); 97 | foreach (var table in tables) 98 | { 99 | if (table.Columns.Any(c => c.IsPrimaryKey)) 100 | { 101 | var pkTypeName = table.Columns.First(m => m.IsPrimaryKey).CSharpType; 102 | Instance.GenerateIService(table.TableName, pkTypeName, ifExistCovered); 103 | } 104 | } 105 | 106 | return this; 107 | } 108 | 109 | public IDbFirst GenerateService(Func selector, bool ifExistCovered = false) 110 | { 111 | var tables = AllTables.Where(selector).ToList(); 112 | foreach (var table in tables) 113 | { 114 | if (table.Columns.Any(c => c.IsPrimaryKey)) 115 | { 116 | var pkTypeName = table.Columns.First(m => m.IsPrimaryKey).CSharpType; 117 | Instance.GenerateService(table.TableName, pkTypeName, ifExistCovered); 118 | } 119 | } 120 | 121 | return this; 122 | } 123 | 124 | public IDbFirst GenerateController(Func selector, bool ifExistCovered = false) 125 | { 126 | var tables = AllTables.Where(selector).ToList(); 127 | foreach (var table in tables) 128 | { 129 | if (table.Columns.Any(c => c.IsPrimaryKey)) 130 | { 131 | var pkTypeName = table.Columns.First(m => m.IsPrimaryKey).CSharpType; 132 | Instance.GenerateController(table.TableName, pkTypeName, ifExistCovered); 133 | } 134 | } 135 | 136 | return this; 137 | } 138 | 139 | public IDbFirst GenerateApiController(Func selector, bool ifExistCovered = false) 140 | { 141 | var tables = AllTables.Where(selector).ToList(); 142 | foreach (var table in tables) 143 | { 144 | if (table.Columns.Any(c => c.IsPrimaryKey)) 145 | { 146 | var pkTypeName = table.Columns.First(m => m.IsPrimaryKey).CSharpType; 147 | Instance.GenerateApiController(table.TableName, pkTypeName, ifExistCovered); 148 | } 149 | } 150 | 151 | return this; 152 | } 153 | 154 | public IDbFirst GenerateViewModel(string viewName, bool ifExistCovered = false) 155 | { 156 | var sql = $"select top 1 * from {viewName}"; 157 | var dt = _dbContext.GetDataTable(sql); 158 | GenerateViewModel(dt, viewName, ifExistCovered); 159 | return this; 160 | } 161 | 162 | public IDbFirst GenerateViewModel(DataTable dt, string className, bool ifExistCovered = false) 163 | { 164 | Instance.GenerateViewModel(dt, className, ifExistCovered); 165 | return this; 166 | } 167 | 168 | public IDbFirst GenerateViewModel(DataSet ds, bool ifExistCovered = false) 169 | { 170 | Instance.GenerateViewModel(ds, ifExistCovered); 171 | return this; 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeGenerator/DbFirst/IDbFirst.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using Zxw.Framework.NetCore.IDbContext; 4 | using Zxw.Framework.NetCore.IoC; 5 | using Zxw.Framework.NetCore.Models; 6 | 7 | namespace Zxw.Framework.NetCore.CodeGenerator.DbFirst 8 | { 9 | public interface IDbFirst 10 | { 11 | void GenerateAll(bool ifExistCovered = false); 12 | IDbFirst Generate(Func selector, bool ifExistCovered = false); 13 | IDbFirst GenerateEntity(Func selector, bool ifExistCovered = false); 14 | IDbFirst GenerateSingle(Func selector, bool ifExistCovered = false); 15 | IDbFirst GenerateIRepository(Func selector, bool ifExistCovered = false); 16 | IDbFirst GenerateRepository(Func selector, bool ifExistCovered = false); 17 | IDbFirst GenerateIService(Func selector, bool ifExistCovered = false); 18 | IDbFirst GenerateService(Func selector, bool ifExistCovered = false); 19 | IDbFirst GenerateController(Func selector, bool ifExistCovered = false); 20 | IDbFirst GenerateApiController(Func selector, bool ifExistCovered = false); 21 | IDbFirst GenerateViewModel(string viewName, bool ifExistCovered = false); 22 | IDbFirst GenerateViewModel(DataTable dt, string className, bool ifExistCovered = false); 23 | IDbFirst GenerateViewModel(DataSet ds, bool ifExistCovered = false); 24 | } 25 | 26 | public static class DbFirstExtensions 27 | { 28 | public static IDbFirst DbFirst(this IDbContextCore dbContext) 29 | { 30 | var dbFirst = ServiceLocator.Resolve(); 31 | if(dbFirst == null) 32 | throw new Exception("请先在Startup.cs文件的ConfigureServices方法中调用UseCodeGenerator方法以注册。"); 33 | return dbFirst; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeTemplate/ApiControllerTemplate.txt: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using Microsoft.AspNetCore.Mvc; 5 | using {ModelsNamespace}; 6 | using {IServicesNamespace}; 7 | using Zxw.Framework.NetCore.Attributes; 8 | using System.Threading.Tasks; 9 | using Zxw.Framework.NetCore.Models; 10 | using System.Linq; 11 | 12 | namespace {ControllersNamespace} 13 | { 14 | [ApiController] 15 | [Route("api/{controller}/{action}")] 16 | public class {ModelTypeName}Controller : ControllerBase 17 | { 18 | private I{ModelTypeName}Service {ModelTypeName}Service; 19 | 20 | public {ModelTypeName}Controller(I{ModelTypeName}Service service) 21 | { 22 | {ModelTypeName}Service = service ?? throw new ArgumentNullException(nameof(service)); 23 | } 24 | 25 | #region Methods 26 | 27 | [HttpGet] 28 | public async Task> GetAll() 29 | { 30 | var rows = {ModelTypeName}Service.Get().Select(m=>new{}).ToList(); 31 | return await Task.FromResult(ExcutedResult.SuccessResult(rows)); 32 | } 33 | 34 | [HttpGet] 35 | public async Task> GetByPaged(int pageSize, int pageIndex) 36 | { 37 | var total = {ModelTypeName}Service.Count(m => true); 38 | var rows = {ModelTypeName}Service.GetByPagination(m => true, pageSize, pageIndex, true, 39 | m => m.Id).Select(m=>new{}).ToList(); 40 | return await Task.FromResult(PaginationResult.PagedResult(rows, total, pageSize, pageIndex)); 41 | } 42 | /// 43 | /// 新建 44 | /// 45 | /// 46 | /// 47 | [HttpPost] 48 | public async Task> Create({ModelTypeName} model) 49 | { 50 | if(!ModelState.IsValid) 51 | return await Task.FromResult(ExcutedResult.FailedResult("数据验证失败")); 52 | {ModelTypeName}Service.AddAsync(model, false); 53 | return await Task.FromResult(ExcutedResult.SuccessResult()); 54 | } 55 | /// 56 | /// 编辑 57 | /// 58 | /// 59 | /// 60 | [HttpPost] 61 | public async Task> Edit({ModelTypeName} model) 62 | { 63 | if (!ModelState.IsValid) 64 | return await Task.FromResult(ExcutedResult.FailedResult("数据验证失败")); 65 | {ModelTypeName}Service.Edit(model, false); 66 | return await Task.FromResult(ExcutedResult.SuccessResult()); 67 | } 68 | /// 69 | /// 删除 70 | /// 71 | /// 72 | /// 73 | [HttpPost] 74 | public async Task> Delete(int id) 75 | { 76 | {ModelTypeName}Service.Delete(id, false); 77 | return await Task.FromResult(ExcutedResult.SuccessResult("成功删除一条数据。")); 78 | } 79 | 80 | #endregion 81 | } 82 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeTemplate/ControllerTemplate.txt: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using Microsoft.AspNetCore.Mvc; 5 | using {ModelsNamespace}; 6 | using {IServicesNamespace}; 7 | using Zxw.Framework.NetCore.Attributes; 8 | using System.Threading.Tasks; 9 | using Zxw.Framework.NetCore.Models; 10 | using System.Linq; 11 | 12 | namespace {ControllersNamespace} 13 | { 14 | public class {ModelTypeName}Controller : Controller 15 | { 16 | private I{ModelTypeName}Service {ModelTypeName}Service; 17 | 18 | public {ModelTypeName}Controller(I{ModelTypeName}Service service) 19 | { 20 | {ModelTypeName}Service = service ?? throw new ArgumentNullException(nameof(service)); 21 | } 22 | 23 | #region Views 24 | 25 | public IActionResult Index() 26 | { 27 | return View(); 28 | } 29 | 30 | #endregion 31 | 32 | #region Methods 33 | 34 | [AjaxRequestOnly, HttpGet] 35 | public Task GetEntities() 36 | { 37 | return Task.Factory.StartNew(() => 38 | { 39 | var rows = {ModelTypeName}Service.Get().ToList(); 40 | return Json(ExcutedResult.SuccessResult(rows)); 41 | }); 42 | } 43 | 44 | [AjaxRequestOnly] 45 | public Task GetEntitiesByPaged(int pageSize, int pageIndex) 46 | { 47 | return Task.Factory.StartNew(() => 48 | { 49 | var total = {ModelTypeName}Service.Count(m => true); 50 | var rows = {ModelTypeName}Service.GetByPagination(m => true, pageSize, pageIndex, true, 51 | m => m.Id).ToList(); 52 | return Json(PaginationResult.PagedResult(rows, total, pageSize, pageIndex)); 53 | }); 54 | } 55 | /// 56 | /// 新建 57 | /// 58 | /// 59 | /// 60 | [AjaxRequestOnly,HttpPost,ValidateAntiForgeryToken] 61 | public Task Add({ModelTypeName} model) 62 | { 63 | return Task.Factory.StartNew(() => 64 | { 65 | if(!ModelState.IsValid) 66 | return Json(ExcutedResult.FailedResult("数据验证失败")); 67 | {ModelTypeName}Service.AddAsync(model, false); 68 | return Json(ExcutedResult.SuccessResult()); 69 | }); 70 | } 71 | /// 72 | /// 编辑 73 | /// 74 | /// 75 | /// 76 | [AjaxRequestOnly, HttpPost] 77 | public Task Edit({ModelTypeName} model) 78 | { 79 | return Task.Factory.StartNew(() => 80 | { 81 | if (!ModelState.IsValid) 82 | return Json(ExcutedResult.FailedResult("数据验证失败")); 83 | {ModelTypeName}Service.Edit(model, false); 84 | return Json(ExcutedResult.SuccessResult()); 85 | }); 86 | } 87 | /// 88 | /// 删除 89 | /// 90 | /// 91 | /// 92 | [AjaxRequestOnly] 93 | public Task Delete(int id) 94 | { 95 | return Task.Factory.StartNew(() => 96 | { 97 | {ModelTypeName}Service.Delete(id, false); 98 | return Json(ExcutedResult.SuccessResult("成功删除一条数据。")); 99 | }); 100 | } 101 | 102 | #endregion 103 | } 104 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeTemplate/IRepositoryTemplate.txt: -------------------------------------------------------------------------------- 1 | using System; 2 | using Zxw.Framework.NetCore.Repositories; 3 | using {ModelsNamespace}; 4 | 5 | namespace {IRepositoriesNamespace} 6 | { 7 | public interface I{ModelTypeName}Repository:IRepository<{ModelTypeName}, {KeyTypeName}> 8 | { 9 | } 10 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeTemplate/IServiceTemplate.txt: -------------------------------------------------------------------------------- 1 | using System; 2 | using Zxw.Framework.NetCore.IServices; 3 | using {ModelsNamespace}; 4 | 5 | namespace {IServicesNamespace} 6 | { 7 | public interface I{ModelTypeName}Service:IService<{ModelTypeName}, {KeyTypeName}> 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeTemplate/ModelTemplate.txt: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using Zxw.Framework.NetCore.Models; 5 | 6 | namespace {ModelsNamespace} 7 | { 8 | /// 9 | /// {Comment} 10 | /// 11 | [Serializable] 12 | [Table("{TableName}")] 13 | public class {ModelName}:BaseModel<{KeyTypeName}> 14 | { 15 | {ModelProperties} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeTemplate/RepositoryTemplate.txt: -------------------------------------------------------------------------------- 1 | using System; 2 | using Zxw.Framework.NetCore.DbContextCore; 3 | using Zxw.Framework.NetCore.Repositories; 4 | using {IRepositoriesNamespace}; 5 | using {ModelsNamespace}; 6 | 7 | namespace {RepositoriesNamespace} 8 | { 9 | public class {ModelTypeName}Repository : BaseRepository<{ModelTypeName}, {KeyTypeName}>, I{ModelTypeName}Repository 10 | { 11 | public {ModelTypeName}Repository(IDbContextCore dbContext) : base(dbContext) 12 | { 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeTemplate/ServiceTemplate.txt: -------------------------------------------------------------------------------- 1 | using System; 2 | using Zxw.Framework.NetCore.Services; 3 | using {IRepositoriesNamespace}; 4 | using {IServicesNamespace}; 5 | using {ModelsNamespace}; 6 | 7 | namespace {ServicesNamespace} 8 | { 9 | public class {ModelTypeName}Service: BaseService<{ModelTypeName}, {KeyTypeName}>, I{ModelTypeName}Service 10 | { 11 | public {ModelTypeName}Service(I{ModelTypeName}Repository repository) : base(repository) 12 | { 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/CodeTemplate/ViewModelTemplate.txt: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace {0} 6 | { 7 | [Table("{1}")] 8 | public class {2}:BaseViewModel 9 | { 10 | {3} 11 | } 12 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Consts/CommonConsts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Zxw.Framework.NetCore.Consts 6 | { 7 | public class AssembleTypeConsts 8 | { 9 | public const string Package = "package"; 10 | public const string ReferenceAssembly = "referenceassembly"; 11 | public const string Project = "project"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbContextCore/DbContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Zxw.Framework.NetCore.Extensions; 3 | using Zxw.Framework.NetCore.IDbContext; 4 | using Zxw.Framework.NetCore.Options; 5 | 6 | namespace Zxw.Framework.NetCore.DbContextCore 7 | { 8 | public class DbContextFactory 9 | { 10 | public static DbContextFactory Instance => new DbContextFactory(); 11 | 12 | public IServiceCollection ServiceCollection { get; set; } 13 | 14 | public DbContextFactory() 15 | { 16 | } 17 | 18 | public void AddDbContext(DbContextOption option) 19 | where TContext : BaseDbContext, IDbContextCore 20 | { 21 | ServiceCollection.AddDbContext(option); 22 | } 23 | 24 | public void AddDbContext(DbContextOption option) 25 | where ITContext : IDbContextCore 26 | where TContext : BaseDbContext, ITContext 27 | { 28 | ServiceCollection.AddDbContext(option); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbContextCore/InMemoryDbContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data; 3 | using System.Data.Common; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.Options; 6 | using Zxw.Framework.NetCore.IDbContext; 7 | using Zxw.Framework.NetCore.Options; 8 | 9 | namespace Zxw.Framework.NetCore.DbContextCore 10 | { 11 | public class InMemoryDbContext:BaseDbContext,IInMemoryDbContext 12 | { 13 | public InMemoryDbContext(DbContextOption option) : base(option) 14 | { 15 | 16 | } 17 | public InMemoryDbContext(IOptions option) : base(option) 18 | { 19 | } 20 | 21 | public InMemoryDbContext(DbContextOptions options) : base(options){} 22 | 23 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 24 | { 25 | optionsBuilder.UseInMemoryDatabase(Option.ConnectionString); 26 | base.OnConfiguring(optionsBuilder); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbContextCore/MySqlDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using System.Data; 5 | using System.Data.Common; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Reflection; 9 | using Microsoft.EntityFrameworkCore; 10 | using Microsoft.Extensions.Options; 11 | using MySqlConnector; 12 | using Zxw.Framework.NetCore.Extensions; 13 | using Zxw.Framework.NetCore.IDbContext; 14 | using Zxw.Framework.NetCore.Options; 15 | 16 | namespace Zxw.Framework.NetCore.DbContextCore 17 | { 18 | public class MySqlDbContext: BaseDbContext, IMySqlDbContext 19 | { 20 | public MySqlDbContext(DbContextOption option) : base(option) 21 | { 22 | 23 | } 24 | public MySqlDbContext(IOptions option) : base(option) 25 | { 26 | } 27 | 28 | public MySqlDbContext(DbContextOptions options) : base(options){} 29 | 30 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 31 | { 32 | optionsBuilder.UseMySql(ServerVersion.AutoDetect(Option.ConnectionString)); 33 | base.OnConfiguring(optionsBuilder); 34 | } 35 | 36 | public override void BulkInsert(IList entities, string destinationTableName = null) 37 | { 38 | if (entities == null || !entities.Any()) return; 39 | if (string.IsNullOrEmpty(destinationTableName)) 40 | { 41 | var mappingTableName = typeof(T).GetCustomAttribute()?.Name; 42 | destinationTableName = string.IsNullOrEmpty(mappingTableName) ? typeof(T).Name : mappingTableName; 43 | } 44 | MySqlBulkInsert(entities, destinationTableName); 45 | } 46 | 47 | private void MySqlBulkInsert(IList entities, string destinationTableName) where T : class 48 | { 49 | var tmpDir = Path.Combine(AppContext.BaseDirectory, "Temp"); 50 | if (!Directory.Exists(tmpDir)) 51 | Directory.CreateDirectory(tmpDir); 52 | var csvFileName = Path.Combine(tmpDir, $"{DateTime.Now:yyyyMMddHHmmssfff}.csv"); 53 | if (!File.Exists(csvFileName)) 54 | File.Create(csvFileName); 55 | var separator = ","; 56 | entities.SaveToCsv(csvFileName, separator); 57 | var conn = (MySqlConnection) Database.GetDbConnection(); 58 | if (conn.State != ConnectionState.Open) 59 | conn.Open(); 60 | var bulk = new MySqlBulkLoader(conn) 61 | { 62 | NumberOfLinesToSkip = 0, 63 | TableName = destinationTableName, 64 | FieldTerminator = separator, 65 | FieldQuotationCharacter = '"', 66 | EscapeCharacter = '"', 67 | LineTerminator = "\r\n" 68 | }; 69 | bulk.LoadAsync(); 70 | conn.Close(); 71 | File.Delete(csvFileName); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbContextCore/OracleDbContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data; 3 | using System.Data.Common; 4 | using System.Linq; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.Extensions.Options; 7 | using Oracle.ManagedDataAccess.Client; 8 | using Zxw.Framework.NetCore.IDbContext; 9 | using Zxw.Framework.NetCore.Options; 10 | 11 | namespace Zxw.Framework.NetCore.DbContextCore 12 | { 13 | public class OracleDbContext:BaseDbContext, IOracleDbContext 14 | { 15 | public OracleDbContext(DbContextOption option) : base(option) 16 | { 17 | 18 | } 19 | public OracleDbContext(IOptions option) : base(option) 20 | { 21 | } 22 | 23 | public OracleDbContext(DbContextOptions options) : base(options){} 24 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 25 | { 26 | optionsBuilder.UseOracle(Option.ConnectionString); 27 | base.OnConfiguring(optionsBuilder); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbContextCore/PostgreSQLDbContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data; 3 | using System.Data.Common; 4 | using System.Linq; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.Extensions.Options; 7 | using Npgsql; 8 | using Zxw.Framework.NetCore.IDbContext; 9 | using Zxw.Framework.NetCore.Options; 10 | 11 | namespace Zxw.Framework.NetCore.DbContextCore 12 | { 13 | public class PostgreSQLDbContext:BaseDbContext, IPostgreSQLDbContext 14 | { 15 | public PostgreSQLDbContext(DbContextOption option) : base(option) 16 | { 17 | 18 | } 19 | public PostgreSQLDbContext(IOptions option) : base(option) 20 | { 21 | } 22 | 23 | public PostgreSQLDbContext(DbContextOptions options) : base(options){} 24 | 25 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 26 | { 27 | optionsBuilder.UseNpgsql(Option.ConnectionString); 28 | base.OnConfiguring(optionsBuilder); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbContextCore/SQLiteDbContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data; 3 | using System.Data.Common; 4 | using System.Linq; 5 | using Microsoft.Data.Sqlite; 6 | using Microsoft.EntityFrameworkCore; 7 | using Microsoft.Extensions.Options; 8 | using Zxw.Framework.NetCore.IDbContext; 9 | using Zxw.Framework.NetCore.Options; 10 | 11 | namespace Zxw.Framework.NetCore.DbContextCore 12 | { 13 | public class SQLiteDbContext:BaseDbContext, ISQLiteDbContext 14 | { 15 | public SQLiteDbContext(DbContextOption option) : base(option) 16 | { 17 | 18 | } 19 | public SQLiteDbContext(IOptions option) : base(option) 20 | { 21 | } 22 | 23 | public SQLiteDbContext(DbContextOptions options) : base(options){} 24 | 25 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 26 | { 27 | optionsBuilder.UseSqlite(Option.ConnectionString); 28 | base.OnConfiguring(optionsBuilder); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbContextCore/ShardDbContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Design; 3 | using Zxw.Framework.NetCore.IoC; 4 | 5 | namespace Zxw.Framework.NetCore.DbContextCore 6 | { 7 | public class ShardDbContextFactory:IDesignTimeDbContextFactory where T:DbContext,new() 8 | { 9 | public T CreateDbContext(string[] args) 10 | { 11 | return ServiceLocator.Resolve(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbContextCore/SqlOperatorUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using System.Data; 5 | using System.Data.Common; 6 | using Microsoft.EntityFrameworkCore; 7 | using Zxw.Framework.NetCore.IDbContext; 8 | using System.Linq; 9 | using System.Reflection; 10 | using System.Text; 11 | using Microsoft.Extensions.Logging; 12 | using Zxw.Framework.NetCore.Extensions; 13 | using Zxw.Framework.NetCore.Helpers; 14 | 15 | namespace Zxw.Framework.NetCore.DbContextCore 16 | { 17 | public class SqlOperatorUtility: ISqlOperatorUtility 18 | { 19 | private IDbContextCore DbContext { get; } 20 | 21 | public SqlOperatorUtility(IDbContextCore context) 22 | { 23 | this.DbContext = context; 24 | } 25 | 26 | private DbConnection GetDbConnection() 27 | { 28 | var connection = DbContext.GetDatabase().GetDbConnection(); 29 | if(connection.State != ConnectionState.Open) 30 | connection.Open(); 31 | return connection; 32 | } 33 | 34 | private DbCommand BuildDbCommand(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, 35 | params DbParameter[] parameters) 36 | { 37 | var cmd = GetDbConnection().CreateCommand(); 38 | cmd.CommandText = sql; 39 | cmd.CommandTimeout = cmdTimeout; 40 | cmd.CommandType = cmdType; 41 | parameters.Each(p => { cmd.Parameters.Add(p); }); 42 | return cmd; 43 | } 44 | private DbCommand BuildDbCommandWithTransaction(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, 45 | params DbParameter[] parameters) 46 | { 47 | var connection = GetDbConnection(); 48 | var cmd = connection.CreateCommand(); 49 | cmd.CommandText = sql; 50 | cmd.CommandTimeout = cmdTimeout; 51 | cmd.CommandType = cmdType; 52 | parameters.Each(p => { cmd.Parameters.Add(p); }); 53 | var tran = connection.BeginTransaction(); 54 | cmd.Transaction = tran; 55 | return cmd; 56 | } 57 | 58 | public DataTable SqlQuery(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, params DbParameter[] parameters) 59 | { 60 | using (var cmd = BuildDbCommand(sql, CommandType.Text, cmdTimeout, parameters)) 61 | { 62 | var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection); 63 | var dt = reader.Fill(); 64 | reader.Close(); 65 | cmd.Connection.Close(); 66 | return dt; 67 | } 68 | } 69 | 70 | public DataSet SqlQuery(List sqlList, int cmdTimeout = 30, params DbParameter[] parameters) 71 | { 72 | var ds = new DataSet(); 73 | var sql = new StringBuilder(); 74 | sqlList.Each(s => sql.AppendLine(s.TrimEnd(';') + ";")); 75 | using (var cmd = BuildDbCommand(sql.ToString(), CommandType.Text, cmdTimeout, parameters)) 76 | { 77 | var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection); 78 | var dt = reader.Fill(); 79 | 80 | ds.Tables.Add(dt); 81 | 82 | while (reader.NextResult()) 83 | { 84 | dt = reader.Fill(); 85 | ds.Tables.Add(dt); 86 | } 87 | 88 | reader.Close(); 89 | cmd.Connection.Close(); 90 | return ds; 91 | } 92 | } 93 | 94 | public IList SqlQuery(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, params DbParameter[] parameters) 95 | { 96 | using (var cmd = BuildDbCommand(sql, cmdType, cmdTimeout, parameters)) 97 | { 98 | var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection); 99 | var list = reader.ToList(); 100 | reader.Close(); 101 | cmd.Connection.Close(); 102 | return list.ToList(); 103 | } 104 | } 105 | 106 | public int ExecuteSqlCommand(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, params DbParameter[] parameters) 107 | { 108 | using (var cmd = BuildDbCommand(sql, cmdType, cmdTimeout, parameters)) 109 | { 110 | var ret = cmd.ExecuteNonQuery(); 111 | cmd.Connection.Close(); 112 | return ret; 113 | } 114 | } 115 | 116 | public int ExecuteSqlCommandWithTransaction(List sqlList, int cmdTimeout = 30, params DbParameter[] parameters) 117 | { 118 | var sql = new StringBuilder(); 119 | sqlList.Each(s => sql.AppendLine(s.TrimEnd(';') + ";")); 120 | using (var cmd = BuildDbCommandWithTransaction(sql.ToString(), CommandType.Text, cmdTimeout, parameters)) 121 | { 122 | var ret = -1; 123 | try 124 | { 125 | ret = cmd.ExecuteNonQuery(); 126 | cmd.Transaction.Commit(); 127 | } 128 | catch (Exception) 129 | { 130 | cmd.Transaction.Rollback(); 131 | throw; 132 | } 133 | finally 134 | { 135 | cmd.Connection.Close(); 136 | } 137 | return ret; 138 | } 139 | } 140 | 141 | public object ExecuteScalar(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, params DbParameter[] parameters) 142 | { 143 | using (var cmd = BuildDbCommand(sql, cmdType, cmdTimeout, parameters)) 144 | { 145 | var ret = cmd.ExecuteScalar(); 146 | cmd.Connection.Close(); 147 | return ret; 148 | } 149 | } 150 | 151 | /// 152 | /// 执行存储过程返回IEnumerable数据集 153 | /// 154 | public IList ExecuteStoredProcedure(string sql, int cmdTimeout = 30, DbParameter[] sqlParams = null) where T : new() 155 | { 156 | return SqlQuery(sql, CommandType.StoredProcedure, cmdTimeout, sqlParams); 157 | } 158 | 159 | public void ClearDataTables(params string[] tables) 160 | { 161 | if (tables == null) 162 | { 163 | var tableList = new List(); 164 | var types = DbContext.GetAllEntityTypes(); 165 | if (types.Any()) 166 | { 167 | foreach (var type in types) 168 | { 169 | var tableName = type.ClrType.GetCustomAttribute()?.Name; 170 | if (tableName.IsNullOrWhiteSpace()) 171 | tableName = type.ClrType.Name; 172 | tableList.Add(tableName); 173 | } 174 | } 175 | else 176 | { 177 | tableList.AddRange(DbContext.GetCurrentDatabaseTableList().Select(m => m.TableName)); 178 | } 179 | 180 | tables = tableList.ToArray(); 181 | } 182 | 183 | var sql = new List(); 184 | foreach (var table in tables) 185 | { 186 | sql.Add($"delete from {table};"); 187 | } 188 | 189 | this.ExecuteSqlCommandWithTransaction(sql); 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbContextCore/SqlServerDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | using System.Data; 6 | using System.Data.Common; 7 | using System.Linq; 8 | using System.Reflection; 9 | using Microsoft.Data.SqlClient; 10 | using Microsoft.EntityFrameworkCore; 11 | using Microsoft.Extensions.Options; 12 | using Zxw.Framework.NetCore.Extensions; 13 | using Zxw.Framework.NetCore.IDbContext; 14 | using Zxw.Framework.NetCore.Models; 15 | using Zxw.Framework.NetCore.Options; 16 | 17 | namespace Zxw.Framework.NetCore.DbContextCore 18 | { 19 | public class SqlServerDbContext:BaseDbContext, ISqlServerDbContext 20 | { 21 | 22 | public SqlServerDbContext(IOptions option) : base(option) 23 | { 24 | } 25 | 26 | public SqlServerDbContext(DbContextOption option) : base(option) 27 | { 28 | 29 | } 30 | //public SqlServerDbContext(DbContextOptions options) : base(options) 31 | //{ 32 | 33 | //} 34 | 35 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 36 | { 37 | optionsBuilder.UseSqlServer(Option.ConnectionString); 38 | base.OnConfiguring(optionsBuilder); 39 | } 40 | 41 | public override void BulkInsert(IList entities, string destinationTableName = null) 42 | { 43 | if (entities == null || !entities.Any()) return; 44 | if (string.IsNullOrEmpty(destinationTableName)) 45 | { 46 | var mappingTableName = typeof(T).GetCustomAttribute()?.Name; 47 | destinationTableName = string.IsNullOrEmpty(mappingTableName) ? typeof(T).Name : mappingTableName; 48 | } 49 | SqlBulkInsert(entities, destinationTableName); 50 | } 51 | 52 | private void SqlBulkInsert(IList entities, string destinationTableName = null) where T : class 53 | { 54 | using (var dt = entities.ToDataTable()) 55 | { 56 | dt.TableName = destinationTableName; 57 | var conn = (SqlConnection)Database.GetDbConnection(); 58 | if (conn.State != ConnectionState.Open) 59 | conn.Open(); 60 | using (var tran = conn.BeginTransaction()) 61 | { 62 | try 63 | { 64 | var bulk = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran) 65 | { 66 | BatchSize = entities.Count, 67 | DestinationTableName = dt.TableName, 68 | }; 69 | GenerateColumnMappings(bulk.ColumnMappings); 70 | bulk.WriteToServerAsync(dt); 71 | tran.Commit(); 72 | } 73 | catch (Exception) 74 | { 75 | tran.Rollback(); 76 | throw; 77 | } 78 | } 79 | conn.Close(); 80 | } 81 | } 82 | 83 | private void GenerateColumnMappings(SqlBulkCopyColumnMappingCollection mappings) 84 | where T : class 85 | { 86 | var properties = typeof(T).GetProperties(); 87 | foreach (var property in properties) 88 | { 89 | if (property.GetCustomAttributes().Any()) 90 | { 91 | mappings.Add(new SqlBulkCopyColumnMapping(property.Name, typeof(T).Name + property.Name)); 92 | } 93 | else 94 | { 95 | mappings.Add(new SqlBulkCopyColumnMapping(property.Name, property.Name)); 96 | } 97 | } 98 | } 99 | 100 | public override PaginationResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize, 101 | Action eachAction = null) 102 | { 103 | var total = SqlQuery($"select count(1) from ({sql}) as s").FirstOrDefault(); 104 | var jsonResults = SqlQuery( 105 | $"select * from (select *,row_number() over (order by {string.Join(",", orderBys)}) as RowId from ({sql}) as s) as t where RowId between {pageSize * (pageIndex - 1) + 1} and {pageSize * pageIndex} order by {string.Join(",", orderBys)}") 106 | .ToList(); 107 | if (eachAction != null) 108 | { 109 | jsonResults = jsonResults.Each(eachAction).ToList(); 110 | } 111 | 112 | return new PaginationResult(true, string.Empty, jsonResults) 113 | { 114 | pageIndex = pageIndex, 115 | pageSize = pageSize, 116 | total = total 117 | }; 118 | } 119 | 120 | public override DataTable GetDataTable(string sql, int cmdTimeout = 30, params DbParameter[] parameters) 121 | { 122 | return GetDataTables(sql, cmdTimeout, parameters).FirstOrDefault(); 123 | } 124 | 125 | public override PaginationResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize, 126 | params DbParameter[] parameters) 127 | { 128 | var total = (int)this.ExecuteScalar($"select count(1) from ({sql}) as s"); 129 | var jsonResults = GetDataTable( 130 | $"select * from (select *,row_number() over (order by {string.Join(",", orderBys)}) as RowId from ({sql}) as s) as t where RowId between {pageSize * (pageIndex - 1) + 1} and {pageSize * pageIndex} order by {string.Join(",", orderBys)}") 131 | .ToList(); 132 | return new PaginationResult(true, string.Empty, jsonResults) 133 | { 134 | pageIndex = pageIndex, 135 | pageSize = pageSize, 136 | total = total 137 | }; 138 | } 139 | 140 | //public override List GetDataTables(string sql, int cmdTimeout = 30, params DbParameter[] parameters) 141 | //{ 142 | // var dts = new List(); 143 | // //TODO: connection 不能dispose 或者 用using,否则下次获取connection会报错提示“the connectionstring property has not been initialized。” 144 | // var connection = Database.GetDbConnection(); 145 | // if (connection.State != ConnectionState.Open) 146 | // connection.Open(); 147 | 148 | // using (var cmd = new SqlCommand(sql, (SqlConnection) connection)) 149 | // { 150 | // cmd.CommandTimeout = cmdTimeout; 151 | // if (parameters != null && parameters.Length > 0) 152 | // { 153 | // cmd.Parameters.AddRange(parameters); 154 | // } 155 | 156 | // using (var da = new SqlDataAdapter(cmd)) 157 | // { 158 | // using (var ds = new DataSet()) 159 | // { 160 | // da.Fill(ds); 161 | // foreach (DataTable table in ds.Tables) 162 | // { 163 | // dts.Add(table); 164 | // } 165 | // } 166 | // } 167 | // } 168 | // connection.Close(); 169 | 170 | // return dts; 171 | //} 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/DbLogProvider/EFLoggerProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace Zxw.Framework.NetCore.DbLogProvider 6 | { 7 | public class EntityFrameworkCommandLoggerFactory : ILoggerFactory 8 | { 9 | public void AddProvider(ILoggerProvider provider) 10 | { 11 | } 12 | 13 | public ILogger CreateLogger(string categoryName) 14 | { 15 | return new EntityFrameworkCommandLogger(categoryName); //创建EFLogger类的实例 16 | } 17 | 18 | public void Dispose() 19 | { 20 | 21 | } 22 | } 23 | 24 | public class EntityFrameworkCommandLogger : ILogger 25 | { 26 | private readonly string categoryName; 27 | 28 | public EntityFrameworkCommandLogger(string categoryName) => this.categoryName = categoryName; 29 | 30 | public virtual bool IsEnabled(LogLevel logLevel) => true; 31 | 32 | public virtual void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, 33 | Func formatter) 34 | { 35 | //ef core执行数据库查询时的categoryName为Microsoft.EntityFrameworkCore.Database.Command,日志级别为Information 36 | if (categoryName == DbLoggerCategory.Database.Command.Name 37 | && logLevel == LogLevel.Information) 38 | { 39 | var logContent = formatter(state, exception); 40 | //TODO: 拿到日志内容想怎么玩就怎么玩吧 41 | Console.WriteLine(); 42 | Console.ForegroundColor = ConsoleColor.Green; 43 | Console.WriteLine(logContent); 44 | Console.ResetColor(); 45 | 46 | this.Log(LogLevel.Trace, logContent); 47 | } 48 | } 49 | 50 | public virtual IDisposable BeginScope(TState state) => null; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Enums/CommonEnums.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Zxw.Framework.NetCore.Enums 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Extensions/CollectionExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Specialized; 4 | using System.Linq.Expressions; 5 | 6 | namespace Zxw.Framework.NetCore.Extensions 7 | { 8 | public static class CollectionExtension 9 | { 10 | /// 11 | /// 添加集合到现有集合中 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// 17 | public static ICollection AddRange(this ICollection list, IEnumerable items) 18 | { 19 | foreach (var current in items) 20 | { 21 | list.Add(current); 22 | } 23 | return list; 24 | } 25 | 26 | /// 27 | /// Each 迭代操作 28 | /// 29 | /// 30 | /// 31 | /// 32 | /// 33 | public static IEnumerable Each(this IEnumerable source, Action action) 34 | { 35 | if (source != null) 36 | { 37 | foreach (var current in source) 38 | { 39 | action(current); 40 | } 41 | } 42 | return source; 43 | } 44 | 45 | /// 46 | /// 将集合转换到 Dictionary 47 | /// 48 | /// 49 | /// 50 | /// 51 | /// 做为键值对 name 的属性。 52 | /// 做为键值对 value 的属性。 53 | /// 54 | public static IDictionary ConvertToDictionary(this ICollection source, 55 | Expression> name, Expression> value) 56 | { 57 | if (name == null) throw new ArgumentNullException(nameof(name), "name 属性不能为空。"); 58 | if (value == null) throw new ArgumentNullException(nameof(value), "value 属性不能为空。"); 59 | 60 | var dict = new Dictionary(); 61 | 62 | source.Each(delegate(T item) { dict.Add(item.GetPropertyValue(name), item.GetPropertyValue(value)); }); 63 | 64 | return dict; 65 | } 66 | 67 | /// 68 | /// 取集合的键值对集合 69 | /// 70 | /// 71 | /// 72 | /// 73 | /// 做为键值对 name 的属性。 74 | /// 做为键值对 value 的属性。 75 | /// 76 | public static NameValueCollection ConvertToNameValueCollection(this ICollection source, 77 | Expression> name, Expression> value) 78 | { 79 | if (name == null) throw new ArgumentNullException(nameof(name), "name 属性不能为空。"); 80 | if (value == null) throw new ArgumentNullException(nameof(value), "value 属性不能为空。"); 81 | 82 | var nvc = new NameValueCollection(); 83 | foreach (var current in source) 84 | { 85 | nvc.Add(current.GetPropertyValue(name).ToString(), current.GetPropertyValue(value).ToString()); 86 | } 87 | return nvc; 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Extensions/Extensions.Mapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using AutoMapper; 5 | 6 | namespace Zxw.Framework.NetCore.Extensions { 7 | /// 8 | /// 对象映射 9 | /// 10 | public static class Extensions { 11 | /// 12 | /// 同步锁 13 | /// 14 | private static readonly object Sync = new object(); 15 | /// 16 | /// 配置提供器 17 | /// 18 | private static IConfigurationProvider _config; 19 | 20 | /// 21 | /// 将源对象映射到目标对象 22 | /// 23 | /// 源类型 24 | /// 目标类型 25 | /// 源对象 26 | /// 目标对象 27 | public static TDestination MapTo( this TSource source, TDestination destination ) { 28 | return MapTo( source, destination ); 29 | } 30 | 31 | /// 32 | /// 将源对象映射到目标对象 33 | /// 34 | /// 目标类型 35 | /// 源对象 36 | public static TDestination MapTo( this object source ) where TDestination : new() { 37 | return MapTo( source, new TDestination() ); 38 | } 39 | 40 | /// 41 | /// 将源对象映射到目标对象 42 | /// 43 | private static TDestination MapTo( object source, TDestination destination ) { 44 | if( source == null ) 45 | return default( TDestination ); 46 | if( destination == null ) 47 | return default( TDestination ); 48 | var sourceType = GetType( source ); 49 | var destinationType = GetType( destination ); 50 | if( Exists( sourceType, destinationType ) ) 51 | return GetResult( source, destination ); 52 | lock( Sync ) { 53 | if( Exists( sourceType, destinationType ) ) 54 | return GetResult( source, destination ); 55 | Init( sourceType, destinationType ); 56 | } 57 | return GetResult( source, destination ); 58 | } 59 | 60 | /// 61 | /// 获取类型 62 | /// 63 | private static Type GetType( object obj ) { 64 | var type = obj.GetType(); 65 | if( ( obj is System.Collections.IEnumerable ) == false ) 66 | return type; 67 | if( type.IsArray ) 68 | return type.GetElementType(); 69 | var genericArgumentsTypes = type.GetTypeInfo().GetGenericArguments(); 70 | if( genericArgumentsTypes == null || genericArgumentsTypes.Length == 0 ) 71 | throw new ArgumentException( "泛型类型参数不能为空" ); 72 | return genericArgumentsTypes[0]; 73 | } 74 | 75 | /// 76 | /// 是否已存在映射配置 77 | /// 78 | private static bool Exists( Type sourceType, Type destinationType ) { 79 | return _config?.FindTypeMapFor( sourceType, destinationType ) != null; 80 | } 81 | 82 | /// 83 | /// 初始化映射配置 84 | /// 85 | private static void Init( Type sourceType, Type destinationType ) { 86 | if( _config == null ) { 87 | _config = new MapperConfiguration( t => t.CreateMap( sourceType, destinationType ) ); 88 | return; 89 | } 90 | var maps = _config.GetAllTypeMaps(); 91 | _config = new MapperConfiguration( t => t.CreateMap( sourceType, destinationType ) ); 92 | foreach( var map in maps ) 93 | _config.RegisterTypeMap( map ); 94 | } 95 | 96 | /// 97 | /// 获取映射结果 98 | /// 99 | private static TDestination GetResult( object source, TDestination destination ) { 100 | return new Mapper( _config ).Map( source, destination ); 101 | } 102 | 103 | /// 104 | /// 将源集合映射到目标集合 105 | /// 106 | /// 目标元素类型,范例:Sample,不要加List 107 | /// 源集合 108 | public static List MapToList( this System.Collections.IEnumerable source ) { 109 | return MapTo>( source ); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Extensions/GenericExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Net; 8 | using System.Reflection; 9 | 10 | namespace Zxw.Framework.NetCore.Extensions 11 | { 12 | /// 13 | /// 泛型扩展 14 | /// 15 | public static class GenericExtension 16 | { 17 | public static bool Equal(this T x, T y) 18 | { 19 | return ((IComparable)(x)).CompareTo(y) == 0; 20 | } 21 | 22 | #region ToDictionary 23 | 24 | public static Dictionary ToDictionary(this T t, Dictionary dic = null) where T : class 25 | { 26 | if (dic == null) 27 | dic = new Dictionary(); 28 | var properties = t.GetType().GetProperties(); 29 | foreach (var property in properties) 30 | { 31 | var value = property.GetValue(t, null); 32 | dic.Add(property.Name, value?.ToString() ?? ""); 33 | } 34 | return dic; 35 | } 36 | 37 | public static Dictionary ToDictionary(this TInterface t, Dictionary dic = null) where T : class, TInterface 38 | { 39 | if (dic == null) 40 | dic = new Dictionary(); 41 | var properties = typeof(T).GetProperties(); 42 | foreach (var property in properties) 43 | { 44 | var value = property.GetValue(t, null); 45 | if (value == null) continue; 46 | dic.Add(property.Name, value?.ToString() ?? ""); 47 | } 48 | return dic; 49 | } 50 | 51 | #endregion 52 | 53 | /// 54 | /// 将字符串转换为指定的类型,如果转换不成功,返回默认值。 55 | /// 56 | /// 结构体类型或枚举类型 57 | /// 需要转换的字符串 58 | /// 返回指定的类型。 59 | public static T ParseTo(this string str) where T : struct 60 | { 61 | return str.ParseTo(default(T)); 62 | } 63 | 64 | /// 65 | /// 将字符串转换为指定的类型,如果转换不成功,返回默认值。 66 | /// 67 | /// 结构体类型或枚举类型 68 | /// 需要转换的字符串 69 | /// 如果转换失败,需要使用的默认值 70 | /// 返回指定的类型。 71 | public static T ParseTo(this string str, T defaultValue) where T : struct 72 | { 73 | var t = str.ParseToNullable(); 74 | if (t.HasValue) 75 | { 76 | return t.Value; 77 | } 78 | return defaultValue; 79 | } 80 | 81 | /// 82 | /// 将字符串转换为指定的类型,如果转换不成功,返回null 83 | /// 84 | /// 结构体类型或枚举类型 85 | /// 需要转换的字符串 86 | /// 返回指定的类型 87 | public static T? ParseToNullable(this string str) where T : struct 88 | { 89 | if (string.IsNullOrEmpty(str)) 90 | { 91 | return null; 92 | } 93 | var typeFromHandle = typeof(T); 94 | if (typeFromHandle.IsEnum) 95 | { 96 | return str.ToEnum(); 97 | } 98 | return (T?)str.ParseTo(typeFromHandle.FullName); 99 | } 100 | 101 | public static DataTable ToDataTable(this IEnumerable source) 102 | { 103 | DataTable dtReturn = new DataTable(); 104 | 105 | 106 | if (source == null) return dtReturn; 107 | // column names 108 | PropertyInfo[] oProps = null; 109 | 110 | foreach (var rec in source) 111 | { 112 | // Use reflection to get property names, to create table, Only first time, others will follow 113 | if (oProps == null) 114 | { 115 | oProps = rec.GetType().GetProperties(); 116 | foreach (var pi in oProps) 117 | { 118 | var colType = pi.PropertyType; 119 | 120 | if (colType.IsNullable()) 121 | { 122 | colType = colType.GetGenericArguments()[0]; 123 | } 124 | if (colType == typeof(Boolean)) 125 | { 126 | colType = typeof(int); 127 | } 128 | 129 | dtReturn.Columns.Add(new DataColumn(pi.Name, colType)); 130 | } 131 | } 132 | 133 | var dr = dtReturn.NewRow(); 134 | 135 | foreach (var pi in oProps) 136 | { 137 | var value = pi.GetValue(rec, null) ?? DBNull.Value; 138 | if (value is bool) 139 | { 140 | dr[pi.Name] = (bool)value ? 1 : 0; 141 | } 142 | else 143 | { 144 | dr[pi.Name] = value; 145 | } 146 | } 147 | 148 | dtReturn.Rows.Add(dr); 149 | } 150 | return dtReturn; 151 | } 152 | 153 | /// 154 | /// 快速复制 155 | /// 156 | /// 157 | /// 158 | /// 159 | /// 160 | public static TOut FastClone(this TIn source) 161 | { 162 | return ObjectFastClone.Clone(source); 163 | } 164 | 165 | /// 166 | /// 对IP地址列表实现排序 167 | /// 168 | /// 169 | /// true为升序,false为降序 170 | /// 171 | public static ICollection Order(this ICollection ips, bool asc = true) 172 | { 173 | if (ips == null) 174 | throw new ArgumentNullException(nameof(ips)); 175 | foreach (var ip in ips) 176 | { 177 | IPAddress tmp; 178 | if (!IPAddress.TryParse(ip, out tmp)) 179 | { 180 | throw new Exception("Illegal IPAdress data."); 181 | } 182 | } 183 | Func func = (s, i) => 184 | { 185 | var tmp = s.Split('.'); 186 | return int.Parse(tmp[i]); 187 | }; 188 | if (asc) 189 | { 190 | return ips.OrderBy(m => func(m, 0)) 191 | .OrderBy(m => func(m, 1)) 192 | .OrderBy(m => func(m, 2)) 193 | .OrderBy(m => func(m, 3)) 194 | .ToList(); 195 | } 196 | return ips.OrderByDescending(m => func(m, 3)) 197 | .OrderByDescending(m => func(m, 2)) 198 | .OrderByDescending(m => func(m, 1)) 199 | .OrderByDescending(m => func(m, 0)) 200 | .ToList(); 201 | } 202 | 203 | public static void SaveToCsv(this IEnumerable source, string csvFullName, string separator=",") 204 | { 205 | if (source == null) 206 | throw new ArgumentNullException(nameof(source)); 207 | if (string.IsNullOrEmpty(separator)) 208 | separator = ","; 209 | var csv = string.Join(separator, source); 210 | using (var sw = new StreamWriter(csvFullName, false)) 211 | { 212 | sw.Write(csv); 213 | sw.Close(); 214 | } 215 | } 216 | } 217 | 218 | /// 219 | /// 运用表达式树实现对象的快速复制 220 | /// 221 | /// 目标对象 222 | /// 输出对象 223 | public class ObjectFastClone 224 | { 225 | private static readonly Func cache = GetFunc(); 226 | private static Func GetFunc() 227 | { 228 | var parameterExpression = Expression.Parameter(typeof(TIn), "p"); 229 | var memberBindingList = new List(); 230 | 231 | foreach (var item in typeof(TOut).GetRuntimeProperties()) 232 | { 233 | var property = Expression.Property(parameterExpression, typeof(TIn).GetRuntimeProperty(item.Name)); 234 | var memberBinding = Expression.Bind(item, property); 235 | memberBindingList.Add(memberBinding); 236 | } 237 | 238 | var memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray()); 239 | var lambda = Expression.Lambda>(memberInitExpression, parameterExpression); 240 | 241 | return lambda.Compile(); 242 | } 243 | 244 | public static TOut Clone(TIn tIn) 245 | { 246 | return cache(tIn); 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Extensions/HttpExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Microsoft.AspNetCore.Http; 4 | 5 | namespace Zxw.Framework.NetCore.Extensions 6 | { 7 | public static class HttpExtensions 8 | { 9 | public static bool IsAjaxRequest(this HttpRequest request) 10 | { 11 | if (request==null) 12 | { 13 | throw new ArgumentNullException(nameof(request)); 14 | } 15 | 16 | return request.Headers.ContainsKey("X-Requested-With") && 17 | request.Headers["X-Requested-With"].Equals("XMLHttpRequest"); 18 | } 19 | 20 | public static string GetUserIp(this HttpContext context) 21 | { 22 | var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); 23 | if (string.IsNullOrEmpty(ip)) 24 | { 25 | ip = context.Connection.RemoteIpAddress.ToString(); 26 | } 27 | return ip; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Extensions/MvcExtension.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace Zxw.Framework.NetCore.Extensions 5 | { 6 | public static class MvcExtension 7 | { 8 | public static T GetService(this HttpContext httpContext) => (T)httpContext.RequestServices.GetService(typeof(T)); 9 | public static T GetService(this ActionContext actionContext) => actionContext.HttpContext.GetService(); 10 | public static T GetService(this Controller controller) => controller.HttpContext.GetService(); 11 | public static T GetService(this ControllerBase controller) => controller.HttpContext.GetService(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Extensions/TypeExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Zxw.Framework.NetCore.Extensions 4 | { 5 | /// 6 | /// Type类的扩展方法 7 | /// 8 | public static class TypeExtension 9 | { 10 | /// 11 | /// 判断是否为基础类型 12 | /// 13 | /// 14 | /// 15 | public static bool IsBulitinType(this Type type) 16 | { 17 | return (type == typeof(object) || Type.GetTypeCode(type) != TypeCode.Object); 18 | } 19 | 20 | public static bool IsNullable(this Type type){ 21 | if(type==null) throw new ArgumentNullException(nameof(type)); 22 | return type.IsGenericType && type.GetGenericTypeDefinition()==typeof(Nullable<>); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Filters/GlobalExceptionFilter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.Filters; 2 | using Zxw.Framework.NetCore.Helpers; 3 | 4 | namespace Zxw.Framework.NetCore.Filters 5 | { 6 | public class GlobalExceptionFilter : IExceptionFilter 7 | { 8 | public void OnException(ExceptionContext filterContext) 9 | { 10 | var type = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType; 11 | Log4NetHelper.WriteError(type, filterContext.Exception); 12 | filterContext.ExceptionHandled = true; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Helpers/AsyncHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace Zxw.Framework.NetCore.Helpers 7 | { 8 | public static class AsyncHelper 9 | { 10 | /// 11 | /// Execute's an async Task method which has a void return value synchronously 12 | /// 13 | /// Task method to execute 14 | public static void RunSync(Func task) 15 | { 16 | var oldContext = SynchronizationContext.Current; 17 | var synch = new ExclusiveSynchronizationContext(); 18 | SynchronizationContext.SetSynchronizationContext(synch); 19 | synch.Post(async _ => 20 | { 21 | try 22 | { 23 | await task(); 24 | } 25 | catch (Exception e) 26 | { 27 | synch.InnerException = e; 28 | throw; 29 | } 30 | finally 31 | { 32 | synch.EndMessageLoop(); 33 | } 34 | }, null); 35 | synch.BeginMessageLoop(); 36 | 37 | SynchronizationContext.SetSynchronizationContext(oldContext); 38 | } 39 | 40 | /// 41 | /// Execute's an async Task method which has a T return type synchronously 42 | /// 43 | /// Return Type 44 | /// Task method to execute 45 | /// 46 | public static T RunSync(Func> task) 47 | { 48 | var oldContext = SynchronizationContext.Current; 49 | var synch = new ExclusiveSynchronizationContext(); 50 | SynchronizationContext.SetSynchronizationContext(synch); 51 | T ret = default(T); 52 | synch.Post(async _ => 53 | { 54 | try 55 | { 56 | ret = await task(); 57 | } 58 | catch (Exception e) 59 | { 60 | synch.InnerException = e; 61 | throw; 62 | } 63 | finally 64 | { 65 | synch.EndMessageLoop(); 66 | } 67 | }, null); 68 | synch.BeginMessageLoop(); 69 | SynchronizationContext.SetSynchronizationContext(oldContext); 70 | return ret; 71 | } 72 | 73 | private class ExclusiveSynchronizationContext : SynchronizationContext 74 | { 75 | private bool done; 76 | public Exception InnerException { get; set; } 77 | readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false); 78 | readonly Queue> items = 79 | new Queue>(); 80 | 81 | public override void Send(SendOrPostCallback d, object state) 82 | { 83 | throw new NotSupportedException("We cannot send to our same thread"); 84 | } 85 | 86 | public override void Post(SendOrPostCallback d, object state) 87 | { 88 | lock (items) 89 | { 90 | items.Enqueue(Tuple.Create(d, state)); 91 | } 92 | workItemsWaiting.Set(); 93 | } 94 | 95 | public void EndMessageLoop() 96 | { 97 | Post(_ => done = true, null); 98 | } 99 | 100 | public void BeginMessageLoop() 101 | { 102 | while (!done) 103 | { 104 | Tuple task = null; 105 | lock (items) 106 | { 107 | if (items.Count > 0) 108 | { 109 | task = items.Dequeue(); 110 | } 111 | } 112 | if (task != null) 113 | { 114 | task.Item1(task.Item2); 115 | if (InnerException != null) // the method threw an exeption 116 | { 117 | throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException); 118 | } 119 | } 120 | else 121 | { 122 | workItemsWaiting.WaitOne(); 123 | } 124 | } 125 | } 126 | 127 | public override SynchronizationContext CreateCopy() 128 | { 129 | return this; 130 | } 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Helpers/CacheKey.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Zxw.Framework.NetCore.Helpers 4 | { 5 | public class CacheKey 6 | { 7 | private MethodInfo Method { get; } 8 | private ParameterInfo[] InputArguments { get; } 9 | private object[] ParameterValues { get; } 10 | 11 | public CacheKey(MethodInfo method, ParameterInfo[] arguments, object[] values) 12 | { 13 | this.Method = method; 14 | this.InputArguments = arguments; 15 | this.ParameterValues = values; 16 | } 17 | 18 | public override bool Equals(object obj) 19 | { 20 | CacheKey another = obj as CacheKey; 21 | if (null == another) 22 | { 23 | return false; 24 | } 25 | if (!this.Method.Equals(another.Method)) 26 | { 27 | return false; 28 | } 29 | for (int index = 0; index < this.InputArguments.Length; index++) 30 | { 31 | var argument1 = this.InputArguments[index]; 32 | var argument2 = another.InputArguments[index]; 33 | if (argument1 == null && argument2 == null) 34 | { 35 | continue; 36 | } 37 | 38 | if (argument1 == null || argument2 == null) 39 | { 40 | return false; 41 | } 42 | 43 | if (!argument1.Equals(argument2)) 44 | { 45 | return false; 46 | } 47 | } 48 | return true; 49 | } 50 | 51 | public string GetRedisCacheKey() 52 | { 53 | return 54 | $"{this.Method.DeclaringType.Namespace}:{this.Method.DeclaringType.Name}:{this.Method.Name}:{GetHashCode()}"; 55 | } 56 | 57 | public string GetMemoryCacheKey() 58 | { 59 | return 60 | $"{this.Method.DeclaringType.Namespace}_{this.Method.DeclaringType.Name}_{this.Method.Name}_{GetHashCode()}"; 61 | } 62 | 63 | public override int GetHashCode() 64 | { 65 | int hashCode = this.Method.GetHashCode(); 66 | foreach (var argument in this.InputArguments) 67 | { 68 | hashCode = hashCode ^ argument.GetHashCode(); 69 | } 70 | 71 | foreach (var value in ParameterValues) 72 | { 73 | hashCode = hashCode ^ value.GetHashCode(); 74 | } 75 | return hashCode; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Helpers/CommonHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Threading; 4 | 5 | namespace Zxw.Framework.NetCore.Helpers 6 | { 7 | public class CommonHelper 8 | { 9 | private static Random rnd = new Random(); 10 | 11 | private static readonly int __staticMachine = ((0x00ffffff & Environment.MachineName.GetHashCode()) + 12 | #if NETSTANDARD1_5 || NETSTANDARD1_6 13 | 1 14 | #else 15 | AppDomain.CurrentDomain.Id 16 | #endif 17 | ) & 0x00ffffff; 18 | private static readonly int __staticPid = Process.GetCurrentProcess().Id; 19 | private static int __staticIncrement = rnd.Next(); 20 | 21 | /// 22 | /// 生成类似Mongodb的ObjectId有序、不重复Guid 23 | /// 24 | /// 25 | public static Guid NewMongodbId() 26 | { 27 | var now = DateTime.Now; 28 | var uninxtime = (int) now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds; 29 | var increment = Interlocked.Increment(ref __staticIncrement) & 0x00ffffff; 30 | var rand = rnd.Next(0, int.MaxValue); 31 | var guid = 32 | $"{uninxtime.ToString("x8").PadLeft(8, '0')}{__staticMachine.ToString("x8").PadLeft(8, '0').Substring(2, 6)}{__staticPid.ToString("x8").PadLeft(8, '0').Substring(6, 2)}{increment.ToString("x8").PadLeft(8, '0')}{rand.ToString("x8").PadLeft(8, '0')}"; 33 | return Guid.Parse(guid); 34 | } 35 | 36 | /// 37 | /// 获取日期差 38 | /// 39 | /// 40 | /// 41 | public static string GetDateDiff(DateTime src) 42 | { 43 | string result = null; 44 | 45 | var currentSecond = (long)(DateTime.Now - src).TotalSeconds; 46 | 47 | long minSecond = 60; //60s = 1min 48 | var hourSecond = minSecond * 60; //60*60s = 1 hour 49 | var daySecond = hourSecond * 24; //60*60*24s = 1 day 50 | var weekSecond = daySecond * 7; //60*60*24*7s = 1 week 51 | var monthSecond = daySecond * 30; //60*60*24*30s = 1 month 52 | var yearSecond = daySecond * 365; //60*60*24*365s = 1 year 53 | 54 | if (currentSecond >= yearSecond) 55 | { 56 | var year = (int)(currentSecond / yearSecond); 57 | result = $"{year}年前"; 58 | } 59 | else if (currentSecond < yearSecond && currentSecond >= monthSecond) 60 | { 61 | var month = (int)(currentSecond / monthSecond); 62 | result = $"{month}个月前"; 63 | } 64 | else if (currentSecond < monthSecond && currentSecond >= weekSecond) 65 | { 66 | var week = (int)(currentSecond / weekSecond); 67 | result = $"{week}周前"; 68 | } 69 | else if (currentSecond < weekSecond && currentSecond >= daySecond) 70 | { 71 | var day = (int)(currentSecond / daySecond); 72 | result = $"{day}天前"; 73 | } 74 | else if (currentSecond < daySecond && currentSecond >= hourSecond) 75 | { 76 | var hour = (int)(currentSecond / hourSecond); 77 | result = $"{hour}小时前"; 78 | } 79 | else if (currentSecond < hourSecond && currentSecond >= minSecond) 80 | { 81 | var min = (int)(currentSecond / minSecond); 82 | result = $"{min}分钟前"; 83 | } 84 | else if (currentSecond < minSecond && currentSecond >= 0) 85 | { 86 | result = "刚刚"; 87 | } 88 | else 89 | { 90 | result = src.ToString("yyyy/MM/dd HH:mm:ss"); 91 | } 92 | return result; 93 | } 94 | 95 | /// 96 | /// 获得类型 97 | /// 98 | /// 99 | /// 100 | public static Type GetTypeByString(string type) 101 | { 102 | switch (type.ToLower()) 103 | { 104 | case "system.boolean": 105 | return Type.GetType("System.Boolean", true, true); 106 | case "system.byte": 107 | return Type.GetType("System.Byte", true, true); 108 | case "system.sbyte": 109 | return Type.GetType("System.SByte", true, true); 110 | case "system.char": 111 | return Type.GetType("System.Char", true, true); 112 | case "system.decimal": 113 | return Type.GetType("System.Decimal", true, true); 114 | case "system.double": 115 | return Type.GetType("System.Double", true, true); 116 | case "system.single": 117 | return Type.GetType("System.Single", true, true); 118 | case "system.int32": 119 | return Type.GetType("System.Int32", true, true); 120 | case "system.uint32": 121 | return Type.GetType("System.UInt32", true, true); 122 | case "system.int64": 123 | return Type.GetType("System.Int64", true, true); 124 | case "system.uint64": 125 | return Type.GetType("System.UInt64", true, true); 126 | case "system.object": 127 | return Type.GetType("System.Object", true, true); 128 | case "system.int16": 129 | return Type.GetType("System.Int16", true, true); 130 | case "system.uint16": 131 | return Type.GetType("System.UInt16", true, true); 132 | case "system.string": 133 | return Type.GetType("System.String", true, true); 134 | case "system.datetime": 135 | case "datetime": 136 | return Type.GetType("System.DateTime", true, true); 137 | case "system.guid": 138 | return Type.GetType("System.Guid", true, true); 139 | default: 140 | return Type.GetType(type, true, true); 141 | } 142 | } 143 | 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Helpers/ConfigHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Zxw.Framework.NetCore.IoC; 3 | 4 | namespace Zxw.Framework.NetCore.Helpers 5 | { 6 | public class ConfigHelper 7 | { 8 | private static IConfiguration configuration = ServiceLocator.Resolve(); 9 | 10 | public static IConfigurationSection GetSection(string key) 11 | { 12 | return configuration.GetSection(key); 13 | } 14 | 15 | public static string GetConfigurationValue(string key) 16 | { 17 | return configuration[key]; 18 | } 19 | 20 | public static string GetConfigurationValue(string section, string key) 21 | { 22 | return GetSection(section)?[key]; 23 | } 24 | 25 | public static string GetConnectionString(string key) 26 | { 27 | return configuration.GetConnectionString(key); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Helpers/EntityMapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Data; 5 | using System.Data.Common; 6 | using System.Reflection; 7 | using System.Reflection.Emit; 8 | 9 | namespace Zxw.Framework.NetCore.Helpers 10 | { 11 | /// 12 | /// 实体类映射,源自SqlSugar(http://www.codeisbug.com/Doc/3/1113) 13 | /// 14 | public static class EntityMapper 15 | { 16 | private delegate T MapEntity(DbDataReader dr); 17 | 18 | //把DataRow转换为对象的委托声明 19 | private delegate T Load(DataRow dataRecord); 20 | 21 | //用于构造Emit的DataRow中获取字段的方法信息 22 | private static readonly MethodInfo getValueMethod = typeof(DataRow).GetMethod("get_Item", new Type[] { typeof(int) }); 23 | 24 | //用于构造Emit的DataRow中判断是否为空行的方法信息 25 | private static readonly MethodInfo isDBNullMethod = typeof(DataRow).GetMethod("IsNull", new Type[] { typeof(int) }); 26 | 27 | 28 | private static readonly ConcurrentDictionary CachedMappers = new ConcurrentDictionary(); 29 | 30 | public static IEnumerable ToList(this DbDataReader dr) 31 | { 32 | // If a mapping function from dr -> T does not exist, create and cache one 33 | if (!CachedMappers.ContainsKey(typeof(T))) 34 | { 35 | // Our method will take in a single parameter, a DbDataReader 36 | Type[] methodArgs = {typeof(DbDataReader)}; 37 | 38 | // The MapDR method will map a DbDataReader row to an instance of type T 39 | DynamicMethod dm = new DynamicMethod("MapDR", typeof(T), methodArgs, 40 | Assembly.GetExecutingAssembly().GetType().Module); 41 | ILGenerator il = dm.GetILGenerator(); 42 | 43 | // We'll have a single local variable, the instance of T we're mapping 44 | il.DeclareLocal(typeof(T)); 45 | 46 | // Create a new instance of T and save it as variable 0 47 | il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); 48 | il.Emit(OpCodes.Stloc_0); 49 | 50 | foreach (PropertyInfo pi in typeof(T).GetProperties()) 51 | { 52 | // Load the T instance, SqlDataReader parameter and the field name onto the stack 53 | il.Emit(OpCodes.Ldloc_0); 54 | il.Emit(OpCodes.Ldarg_0); 55 | il.Emit(OpCodes.Ldstr, pi.Name); 56 | 57 | // Push the column value onto the stack 58 | il.Emit(OpCodes.Callvirt, typeof(DbDataReader).GetMethod("get_Item", new Type[] {typeof(string)})); 59 | 60 | // Depending on the type of the property, convert the datareader column value to the type 61 | switch (pi.PropertyType.Name) 62 | { 63 | case "Int16": 64 | il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt16", new Type[] {typeof(object)})); 65 | break; 66 | case "Int32": 67 | il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] {typeof(object)})); 68 | break; 69 | case "Int64": 70 | il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt64", new Type[] {typeof(object)})); 71 | break; 72 | case "Boolean": 73 | il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToBoolean", new Type[] {typeof(object)})); 74 | break; 75 | case "String": 76 | il.Emit(OpCodes.Callvirt, typeof(string).GetMethod("ToString", new Type[] { })); 77 | break; 78 | case "DateTime": 79 | il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToDateTime", new Type[] {typeof(object)})); 80 | break; 81 | case "Decimal": 82 | il.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToDecimal", new Type[] {typeof(object)})); 83 | break; 84 | default: 85 | // Don't set the field value as it's an unsupported type 86 | continue; 87 | } 88 | 89 | // Set the T instances property value 90 | il.Emit(OpCodes.Callvirt, typeof(T).GetMethod("set_" + pi.Name, new Type[] {pi.PropertyType})); 91 | } 92 | 93 | // Load the T instance onto the stack 94 | il.Emit(OpCodes.Ldloc_0); 95 | 96 | // Return 97 | il.Emit(OpCodes.Ret); 98 | 99 | // Cache the method so we won't have to create it again for the type T 100 | CachedMappers.TryAdd(typeof(T), dm.CreateDelegate(typeof(MapEntity))); 101 | } 102 | 103 | // Get a delegate reference to the dynamic method 104 | MapEntity invokeMapEntity = (MapEntity) CachedMappers[typeof(T)]; 105 | 106 | // For each row, map the row to an instance of T and yield return it 107 | while (dr.Read()) 108 | yield return invokeMapEntity(dr); 109 | } 110 | 111 | /// 112 | /// 将DataTable转换成泛型对象列表 113 | /// 114 | /// 115 | /// 116 | /// 117 | public static List ToList(this DataTable dt) 118 | { 119 | List list = new List(); 120 | if (dt == null) 121 | return list; 122 | 123 | //声明 委托Load的一个实例rowMap 124 | Load rowMap = null; 125 | 126 | 127 | //从rowMapMethods查找当前T类对应的转换方法,没有则使用Emit构造一个。 128 | if (!CachedMappers.ContainsKey(typeof(T))) 129 | { 130 | DynamicMethod method = new DynamicMethod("DynamicCreateEntity_" + typeof(T).Name, typeof(T), new Type[] { typeof(DataRow) }, typeof(T), true); 131 | ILGenerator generator = method.GetILGenerator(); 132 | LocalBuilder result = generator.DeclareLocal(typeof(T)); 133 | generator.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); 134 | generator.Emit(OpCodes.Stloc, result); 135 | 136 | for (int index = 0; index < dt.Columns.Count; index++) 137 | { 138 | PropertyInfo propertyInfo = typeof(T).GetProperty(dt.Columns[index].ColumnName); 139 | Label endIfLabel = generator.DefineLabel(); 140 | if (propertyInfo != null && propertyInfo.GetSetMethod() != null) 141 | { 142 | generator.Emit(OpCodes.Ldarg_0); 143 | generator.Emit(OpCodes.Ldc_I4, index); 144 | generator.Emit(OpCodes.Callvirt, isDBNullMethod); 145 | generator.Emit(OpCodes.Brtrue, endIfLabel); 146 | generator.Emit(OpCodes.Ldloc, result); 147 | generator.Emit(OpCodes.Ldarg_0); 148 | generator.Emit(OpCodes.Ldc_I4, index); 149 | generator.Emit(OpCodes.Callvirt, getValueMethod); 150 | generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); 151 | generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod()); 152 | generator.MarkLabel(endIfLabel); 153 | } 154 | } 155 | generator.Emit(OpCodes.Ldloc, result); 156 | generator.Emit(OpCodes.Ret); 157 | 158 | //构造完成以后传给rowMap 159 | rowMap = (Load)method.CreateDelegate(typeof(Load)); 160 | } 161 | else 162 | { 163 | rowMap = (Load)CachedMappers[typeof(T)]; 164 | } 165 | 166 | //遍历Datatable的rows集合,调用rowMap把DataRow转换为对象(T) 167 | foreach (DataRow info in dt.Rows) 168 | list.Add(rowMap(info)); 169 | return list; 170 | } 171 | 172 | public static void ClearCachedMapperMethods() 173 | { 174 | CachedMappers.Clear(); 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Helpers/HttpRequestHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Text; 7 | using Newtonsoft.Json; 8 | 9 | namespace Zxw.Framework.NetCore.Helpers 10 | { 11 | [Obsolete("请使用HttpClient")] 12 | public static class HttpRequestHelper 13 | { 14 | #region 同步方法 15 | 16 | /// 17 | /// 使用Get方法获取字符串结果(加入Cookie) 18 | /// 19 | /// 20 | /// 21 | /// 22 | public static string HttpGet(string url, Encoding encoding = null, int timeOut = 60000) 23 | { 24 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 25 | request.Method = "GET"; 26 | request.Timeout = timeOut; 27 | 28 | //if (cookieContainer != null) 29 | //{ 30 | // request.CookieContainer = cookieContainer; 31 | //} 32 | 33 | HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 34 | 35 | //if (cookieContainer != null) 36 | //{ 37 | // response.Cookies = cookieContainer.GetCookies(response.ResponseUri); 38 | //} 39 | 40 | using (Stream responseStream = response.GetResponseStream()) 41 | { 42 | using (StreamReader myStreamReader = new StreamReader(responseStream, encoding ?? Encoding.GetEncoding("utf-8"))) 43 | { 44 | string retString = myStreamReader.ReadToEnd(); 45 | return retString; 46 | } 47 | } 48 | } 49 | 50 | /// 51 | /// 使用Post方法获取字符串结果,常规提交 52 | /// 53 | /// 54 | public static string HttpPost(string url, Dictionary formData = null, Encoding encoding = null, int timeOut = 60000, Dictionary headers = null) 55 | { 56 | MemoryStream ms = new MemoryStream(); 57 | formData.FillFormDataStream(ms);//填充formData 58 | return HttpPost(url, ms, "application/x-www-form-urlencoded", encoding, headers, timeOut); 59 | } 60 | 61 | /// 62 | /// 发送HttpPost请求,使用JSON格式传输数据 63 | /// 64 | /// 65 | /// 66 | /// 67 | /// 68 | public static string HttpPost(string url, string postData, Encoding encoding = null, Dictionary headers = null) 69 | { 70 | if (encoding == null) 71 | encoding = Encoding.UTF8; 72 | if (string.IsNullOrWhiteSpace(postData)) 73 | throw new ArgumentNullException("postData"); 74 | byte[] data = encoding.GetBytes(postData); 75 | MemoryStream stream = new MemoryStream(); 76 | var formDataBytes = postData == null ? new byte[0] : Encoding.UTF8.GetBytes(postData); 77 | stream.Write(formDataBytes, 0, formDataBytes.Length); 78 | stream.Seek(0, SeekOrigin.Begin);//设置指针读取位置 79 | return HttpPost(url, stream, "application/json", encoding, headers); 80 | } 81 | 82 | /// 83 | /// 使用POST请求数据,使用JSON传输数据 84 | /// 85 | /// 86 | /// 传输对象,转换为JSON传输 87 | /// 88 | /// 89 | public static string HttpPost(string url, object dataObj, Encoding encoding = null, Dictionary headers = null) 90 | { 91 | if (encoding == null) 92 | encoding = Encoding.UTF8; 93 | if (dataObj == null) 94 | throw new ArgumentNullException("dataObj"); 95 | string postData = JsonConvert.SerializeObject(dataObj, new JsonSerializerSettings(){DateFormatString = "yyyy-MM-dd HH:mm:ss"}); 96 | byte[] data = encoding.GetBytes(postData); 97 | MemoryStream stream = new MemoryStream(); 98 | var formDataBytes = postData == null ? new byte[0] : Encoding.UTF8.GetBytes(postData); 99 | stream.Write(formDataBytes, 0, formDataBytes.Length); 100 | stream.Seek(0, SeekOrigin.Begin);//设置指针读取位置 101 | return HttpPost(url, stream, "application/json", encoding, headers); 102 | } 103 | 104 | /// 105 | /// 使用Post方法获取字符串结果 106 | /// 107 | /// 108 | /// 109 | /// 110 | /// 111 | /// 112 | /// 113 | public static string HttpPost(string url, Stream postStream = null, string contentType = "application/x-www-form-urlencoded", Encoding encoding = null, Dictionary headers=null, int timeOut = 60000) 114 | { 115 | HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 116 | request.Method = "POST"; 117 | request.Timeout = timeOut; 118 | 119 | request.ContentLength = postStream != null ? postStream.Length : 0; 120 | request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"; 121 | request.KeepAlive = false; 122 | 123 | request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.87 Safari/537.36 QQBrowser/9.2.5748.400"; 124 | request.ContentType = contentType; 125 | 126 | //request.Headers.Add("Access-Control-Allow-Origin","http://517best.com"); 127 | if (headers != null) 128 | { 129 | foreach (var header in headers) 130 | { 131 | request.Headers.Add(header.Key, header.Value); 132 | } 133 | } 134 | 135 | #region 输入二进制流 136 | if (postStream != null) 137 | { 138 | postStream.Position = 0; 139 | 140 | //直接写入流 141 | Stream requestStream = request.GetRequestStream(); 142 | 143 | byte[] buffer = new byte[1024]; 144 | int bytesRead = 0; 145 | while ((bytesRead = postStream.Read(buffer, 0, buffer.Length)) != 0) 146 | { 147 | requestStream.Write(buffer, 0, bytesRead); 148 | } 149 | 150 | postStream.Close();//关闭文件访问 151 | } 152 | #endregion 153 | 154 | HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 155 | 156 | using (Stream responseStream = response.GetResponseStream()) 157 | { 158 | using (StreamReader myStreamReader = new StreamReader(responseStream, encoding ?? Encoding.GetEncoding("utf-8"))) 159 | { 160 | string retString = myStreamReader.ReadToEnd(); 161 | return retString; 162 | } 163 | } 164 | } 165 | 166 | #endregion 167 | 168 | public static void FillFormDataStream(this Dictionary formData, Stream stream) 169 | { 170 | string dataString = GetQueryString(formData); 171 | var formDataBytes = formData == null ? new byte[0] : Encoding.UTF8.GetBytes(dataString); 172 | stream.Write(formDataBytes, 0, formDataBytes.Length); 173 | stream.Seek(0, SeekOrigin.Begin);//设置指针读取位置 174 | } 175 | 176 | /// 177 | /// 组装QueryString的方法 178 | /// 参数之间用&连接,首位没有符号,如:a=1&b=2&c=3 179 | /// 180 | /// 181 | /// 182 | public static string GetQueryString(this Dictionary formData) 183 | { 184 | if (formData == null || formData.Count == 0) 185 | { 186 | return ""; 187 | } 188 | StringBuilder sb = new StringBuilder(); 189 | var i = 0; 190 | foreach (var kv in formData) 191 | { 192 | i++; 193 | sb.AppendFormat("{0}={1}", kv.Key, kv.Value); 194 | if (i < formData.Count) 195 | { 196 | sb.Append("&"); 197 | } 198 | } 199 | return sb.ToString(); 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Helpers/JsonConvertor.cs: -------------------------------------------------------------------------------- 1 | using Jil; 2 | using System; 3 | 4 | namespace Zxw.Framework.NetCore.Helpers 5 | { 6 | /// 7 | /// json serialization and deserialization, using Jil. 8 | /// 9 | public class JsonConvertor 10 | { 11 | public static string Serialize(object source, Jil.Options options = null) 12 | { 13 | return JSON.Serialize(source, options); 14 | } 15 | public static string Serialize(T source, Jil.Options options = null) 16 | { 17 | return JSON.Serialize(source, options); 18 | } 19 | 20 | public static T Deserialize(string source, Jil.Options options = null) 21 | { 22 | return JSON.Deserialize(source, options); 23 | } 24 | 25 | public static object Deserialize(string source, Type destinationType, Jil.Options options = null) 26 | { 27 | return JSON.Deserialize(source, destinationType, options); 28 | } 29 | 30 | public static dynamic Deserialize(string source, Jil.Options options = null) 31 | { 32 | return JSON.DeserializeDynamic(source, options); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Helpers/Log4netHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using Exceptionless; 5 | using Exceptionless.Logging; 6 | using log4net; 7 | using log4net.Config; 8 | using log4net.Repository; 9 | using Zxw.Framework.NetCore.Extensions; 10 | 11 | namespace Zxw.Framework.NetCore.Helpers 12 | { 13 | /// 14 | /// log4net封装类 15 | /// *********************************使用说明********************************** 16 | /// 1.首先将配置文件(log4net.config或App.config)放置在程序运行目录 17 | /// 2.调用SetConfig方法,并传入配置文件的全路径 18 | /// 3.调用WriteError、WriteInfo、WriteFatal、WriteDebug等方法 19 | /// 20 | public class Log4NetHelper 21 | { 22 | private static ILoggerRepository _repository; 23 | private static bool _bLog2Exceptionless = false; 24 | private static ExceptionlessClient exceptionlessClient = null; 25 | 26 | /// 27 | /// 读取配置文件,并使其生效。如果未找到配置文件,则抛出异常 28 | /// 29 | /// 30 | /// 配置文件全路径 31 | /// 是否启用Exceptionless 32 | public static void SetConfig(ILoggerRepository repository, string configFilePath, bool useExceptionless = false) 33 | { 34 | _repository = repository; 35 | var fileInfo = new FileInfo(configFilePath); 36 | if (!fileInfo.Exists) 37 | { 38 | throw new Exception("未找到配置文件" + configFilePath); 39 | } 40 | XmlConfigurator.ConfigureAndWatch(_repository, fileInfo); 41 | 42 | _bLog2Exceptionless = useExceptionless; 43 | if (_bLog2Exceptionless) 44 | { 45 | exceptionlessClient = ExceptionlessClient.Default; 46 | } 47 | } 48 | 49 | #region static void WriteError(Type t, Exception ex) 50 | 51 | /// 52 | /// 输出错误日志到Log4Net 53 | /// 54 | /// 55 | /// 56 | public static void WriteError(Type t, Exception ex) 57 | { 58 | var log = LogManager.GetLogger(_repository.Name, t); 59 | log.Error("Error", ex); 60 | WriteExceptionlessLog(ex.Source, ex.Message, LogLevel.Error); 61 | } 62 | 63 | #endregion static void WriteError(Type t, Exception ex) 64 | 65 | #region static void WriteError(Type t, string msg) 66 | 67 | /// 68 | /// 输出错误日志到Log4Net 69 | /// 70 | /// 71 | /// 72 | public static void WriteError(Type t, string msg) 73 | { 74 | var log = LogManager.GetLogger(_repository.Name, t); 75 | var stackTrace = new StackTrace(); 76 | var stackFrame = stackTrace.GetFrame(1); 77 | var methodBase = stackFrame.GetMethod(); 78 | var message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; 79 | log.Error(message); 80 | WriteExceptionlessLog(null, message, LogLevel.Error); 81 | } 82 | 83 | #endregion static void WriteError(Type t, string msg) 84 | 85 | /// 86 | /// 记录消息日志 87 | /// 88 | /// 89 | /// 90 | public static void WriteInfo(Type t, string msg) 91 | { 92 | var log = LogManager.GetLogger(_repository.Name, t); 93 | var stackTrace = new StackTrace(); 94 | var stackFrame = stackTrace.GetFrame(1); 95 | var methodBase = stackFrame.GetMethod(); 96 | var message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; 97 | log.Info(message); 98 | 99 | WriteExceptionlessLog(null, message, LogLevel.Info); 100 | } 101 | 102 | /// 103 | /// 记录消息日志 104 | /// 105 | /// 106 | /// 107 | public static void WriteInfo(Type t, Exception exception) 108 | { 109 | var log = LogManager.GetLogger(_repository.Name, t); 110 | log.Info("系统消息", exception); 111 | WriteExceptionlessLog(exception.Source, exception.Message, LogLevel.Info); 112 | } 113 | 114 | /// 115 | /// 记录致命错误日志 116 | /// 117 | /// 118 | /// 119 | public static void WriteFatal(Type t, string msg) 120 | { 121 | var log = LogManager.GetLogger(_repository.Name, t); 122 | var stackTrace = new StackTrace(); 123 | var stackFrame = stackTrace.GetFrame(1); 124 | var methodBase = stackFrame.GetMethod(); 125 | var message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; 126 | log.Fatal(message); 127 | WriteExceptionlessLog(null, message, LogLevel.Fatal); 128 | } 129 | 130 | /// 131 | /// 记录致命错误日志 132 | /// 133 | /// 134 | /// 135 | public static void WriteFatal(Type t, Exception exception) 136 | { 137 | var log = LogManager.GetLogger(_repository.Name, t); 138 | log.Fatal("系统致命错误", exception); 139 | WriteExceptionlessLog(exception.Source, exception.Message, LogLevel.Fatal); 140 | } 141 | 142 | /// 143 | /// 记录Debug日志 144 | /// 145 | /// 146 | /// 147 | public static void WriteDebug(Type t, string msg) 148 | { 149 | var log = LogManager.GetLogger(_repository.Name, t); 150 | var stackTrace = new StackTrace(); 151 | var stackFrame = stackTrace.GetFrame(1); 152 | var methodBase = stackFrame.GetMethod(); 153 | var message = "方法名称:" + methodBase.Name + "\r\n日志内容:" + msg; 154 | log.Debug(message); 155 | WriteExceptionlessLog(null, message, LogLevel.Debug); 156 | } 157 | 158 | /// 159 | /// 记录Debug日志 160 | /// 161 | /// 162 | /// 163 | public static void WriteDebug(Type t, Exception exception) 164 | { 165 | var log = LogManager.GetLogger(_repository.Name, t); 166 | log.Debug("系统调试信息", exception); 167 | WriteExceptionlessLog(exception.Source, exception.Message, LogLevel.Debug); 168 | } 169 | 170 | /// 171 | /// 记录警告信息 172 | /// 173 | /// 174 | /// 175 | public static void WriteWarn(Type t, string msg) 176 | { 177 | var log = LogManager.GetLogger(_repository.Name, t); 178 | log.Warn(msg); 179 | WriteExceptionlessLog(null, msg, LogLevel.Warn); 180 | } 181 | 182 | /// 183 | /// 记录警告信息 184 | /// 185 | /// 186 | /// 187 | public static void WriteWarn(Type t, Exception exception) 188 | { 189 | var log = LogManager.GetLogger(_repository.Name, t); 190 | log.Warn("系统警告信息", exception); 191 | WriteExceptionlessLog(exception.Source, exception.Message, LogLevel.Warn); 192 | } 193 | 194 | private static void WriteExceptionlessLog(string source, string message, LogLevel logLevel, params string[] tags) 195 | { 196 | if (source.IsNullOrWhiteSpace()) 197 | exceptionlessClient?.CreateLog(message, logLevel).AddTags(tags).Submit(); 198 | else 199 | exceptionlessClient?.CreateLog(source, message, logLevel).AddTags(tags).Submit(); 200 | } 201 | } 202 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Helpers/RuntimeHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Runtime.Loader; 6 | using Microsoft.Extensions.DependencyModel; 7 | using Zxw.Framework.NetCore.Consts; 8 | 9 | namespace Zxw.Framework.NetCore.Helpers 10 | { 11 | public class RuntimeHelper 12 | { 13 | /// 14 | /// 获取项目程序集,排除所有的系统程序集(Microsoft.***、System.***等)、Nuget下载包 15 | /// 16 | /// 17 | public static IList GetAllAssemblies() 18 | { 19 | var list = new List(); 20 | var deps = DependencyContext.Default; 21 | //var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package" && lib.Type!= "referenceassembly");//排除所有的系统程序集、Nuget下载包 22 | var libs = deps.CompileLibraries.Where(lib => lib.Type == AssembleTypeConsts.Project);//只获取本项目用到的包 23 | foreach (var lib in libs) 24 | { 25 | try 26 | { 27 | var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name)); 28 | list.Add(assembly); 29 | } 30 | catch (Exception) 31 | { 32 | // ignored 33 | } 34 | } 35 | return list; 36 | } 37 | 38 | public static Assembly GetAssembly(string assemblyName) 39 | { 40 | return GetAllAssemblies().FirstOrDefault(assembly => assembly.FullName.Contains(assemblyName)); 41 | } 42 | 43 | public static IList GetAllTypes() 44 | { 45 | var list = new List(); 46 | foreach (var assembly in GetAllAssemblies()) 47 | { 48 | var typeInfos = assembly.DefinedTypes; 49 | foreach (var typeInfo in typeInfos) 50 | { 51 | list.Add(typeInfo.AsType()); 52 | } 53 | } 54 | return list; 55 | } 56 | 57 | public static IList GetTypesByAssembly(string assemblyName) 58 | { 59 | var list = new List(); 60 | var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName)); 61 | var typeInfos = assembly.DefinedTypes; 62 | foreach (var typeInfo in typeInfos) 63 | { 64 | list.Add(typeInfo.AsType()); 65 | } 66 | return list; 67 | } 68 | 69 | public static Type GetImplementType(string typeName, Type baseInterfaceType) 70 | { 71 | return GetAllTypes().FirstOrDefault(t => 72 | { 73 | if (t.Name == typeName && 74 | t.GetTypeInfo().GetInterfaces().Any(b => b.Name == baseInterfaceType.Name)) 75 | { 76 | var typeInfo = t.GetTypeInfo(); 77 | return typeInfo.IsClass && !typeInfo.IsAbstract && !typeInfo.IsGenericType; 78 | } 79 | return false; 80 | }); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IDbContext/IDbContextCore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Data.Common; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using AspectCore.DynamicProxy; 10 | using Microsoft.EntityFrameworkCore; 11 | using Microsoft.EntityFrameworkCore.Infrastructure; 12 | using Microsoft.EntityFrameworkCore.Metadata; 13 | using Zxw.Framework.NetCore.Models; 14 | using Zxw.Framework.NetCore.Options; 15 | 16 | namespace Zxw.Framework.NetCore.IDbContext 17 | { 18 | [NonAspect] 19 | public interface IDbContextCore: IDisposable 20 | { 21 | DbContextOption Option { get; } 22 | DatabaseFacade GetDatabase(); 23 | T GetService() where T : class, new(); 24 | int Add(T entity) where T : class; 25 | Task AddAsync(T entity) where T : class; 26 | int AddRange(ICollection entities) where T : class; 27 | Task AddRangeAsync(ICollection entities) where T : class; 28 | int Count(Expression> @where = null) where T : class; 29 | Task CountAsync(Expression> @where = null) where T : class; 30 | int Delete(TKey key) where T : BaseModel; 31 | bool EnsureCreated(); 32 | Task EnsureCreatedAsync(); 33 | int ExecuteSqlWithNonQuery(string sql, params object[] parameters); 34 | Task ExecuteSqlWithNonQueryAsync(string sql, params object[] parameters); 35 | int Edit(T entity) where T : class; 36 | int EditRange(ICollection entities) where T : class; 37 | bool Exist(Expression> @where = null) where T : class; 38 | IQueryable FilterWithInclude(Func, IQueryable> include, Expression> where) where T : class; 39 | Task ExistAsync(Expression> @where = null) where T : class; 40 | T Find(object key) where T : class; 41 | T Find(TKey key) where T : BaseModel; 42 | Task FindAsync(object key) where T : class; 43 | Task FindAsync(TKey key) where T : BaseModel; 44 | IQueryable Get(Expression> @where = null, bool asNoTracking = false) where T : class; 45 | List GetAllEntityTypes(); 46 | DbSet GetDbSet() where T : class; 47 | T GetSingleOrDefault(Expression> @where = null) where T : class; 48 | Task GetSingleOrDefaultAsync(Expression> @where = null) where T : class; 49 | int Update(T model, params string[] updateColumns) where T : class; 50 | int Update(Expression> @where, Expression> updateFactory) where T : class; 51 | Task UpdateAsync(Expression> @where, Expression> updateFactory) 52 | where T : class; 53 | int Delete(Expression> @where) where T : class; 54 | Task DeleteAsync(Expression> @where) where T : class; 55 | void BulkInsert(IList entities, string destinationTableName = null) 56 | where T : class ; 57 | List SqlQuery(string sql, params object[] parameters) 58 | where T : class; 59 | List SqlQuery(string sql, int cmdTimeout = 30, params object[] parameters); 60 | PaginationResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize, Action eachAction = null) 61 | where T : class 62 | where TView : class; 63 | int SaveChanges(); 64 | int SaveChanges(bool acceptAllChangesOnSuccess); 65 | Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)); 66 | Task SaveChangesAsync(bool acceptAllChangesOnSuccess,CancellationToken cancellationToken = default(CancellationToken)); 67 | DataTable GetDataTable(string sql, int cmdTimeout = 30, params DbParameter[] parameters); 68 | PaginationResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize, 69 | params DbParameter[] parameters) where T : class, new(); 70 | List GetDataTables(string sql, int cmdTimeout=30, params DbParameter[] parameters); 71 | T GetByCompileQuery(TKey id) where T : BaseModel; 72 | Task GetByCompileQueryAsync(TKey id) where T : BaseModel; 73 | IList GetByCompileQuery(Expression> filter) where T : class; 74 | Task> GetByCompileQueryAsync(Expression> filter) where T : class; 75 | T FirstOrDefaultByCompileQuery(Expression> filter) where T : class; 76 | Task FirstOrDefaultByCompileQueryAsync(Expression> filter) where T : class; 77 | T FirstOrDefaultWithTrackingByCompileQuery(Expression> filter) where T : class; 78 | Task FirstOrDefaultWithTrackingByCompileQueryAsync(Expression> filter) where T : class; 79 | int CountByCompileQuery(Expression> filter) where T : class; 80 | Task CountByCompileQueryAsync(Expression> filter) where T : class; 81 | } 82 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IDbContext/IInMemoryDbContext.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.IDbContext 2 | { 3 | public interface IInMemoryDbContext:IDbContextCore 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IDbContext/IMongoDbContext.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.IDbContext 2 | { 3 | public interface IMongoDbContext:IDbContextCore 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IDbContext/IMySqlDbContext.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.IDbContext 2 | { 3 | public interface IMySqlDbContext:IDbContextCore 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IDbContext/IOracleDbContext.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.IDbContext 2 | { 3 | public interface IOracleDbContext:IDbContextCore 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IDbContext/IPostgreSQLDbContext.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.IDbContext 2 | { 3 | public interface IPostgreSQLDbContext:IDbContextCore 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IDbContext/ISQLiteDbContext.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.IDbContext 2 | { 3 | public interface ISQLiteDbContext:IDbContextCore 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IDbContext/ISqlOperatorUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Data.Common; 5 | using System.Text; 6 | using Zxw.Framework.NetCore.IoC; 7 | 8 | namespace Zxw.Framework.NetCore.IDbContext 9 | { 10 | public interface ISqlOperatorUtility: IScopedDependency 11 | { 12 | DataTable SqlQuery(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, params DbParameter[] parameters); 13 | DataSet SqlQuery(List sqlList, int cmdTimeout = 30, params DbParameter[] parameters); 14 | IList SqlQuery(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, params DbParameter[] parameters); 15 | int ExecuteSqlCommand(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, params DbParameter[] parameters); 16 | int ExecuteSqlCommandWithTransaction(List sqlList, int cmdTimeout = 30, 17 | params DbParameter[] parameters); 18 | 19 | IList ExecuteStoredProcedure(string sql, int cmdTimeout = 30, DbParameter[] sqlParams = null) 20 | where T : new(); 21 | object ExecuteScalar(string sql, CommandType cmdType = CommandType.Text, int cmdTimeout = 30, params DbParameter[] parameters); 22 | void ClearDataTables(params string[] tables); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IDbContext/ISqlServerDbContext.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.IDbContext 2 | { 3 | public interface ISqlServerDbContext:IDbContextCore 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IoC/AspectCoreContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using AspectCore.Configuration; 5 | using AspectCore.DependencyInjection; 6 | using AspectCore.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Zxw.Framework.NetCore.Extensions; 9 | using Zxw.Framework.NetCore.IDbContext; 10 | using LightInject; 11 | 12 | namespace Zxw.Framework.NetCore.IoC 13 | { 14 | public class AspectCoreContainer 15 | { 16 | private static IServiceResolver resolver { get; set; } 17 | public static IServiceProvider BuildServiceProvider(IServiceCollection services, Action configure = null) 18 | { 19 | if(services==null)throw new ArgumentNullException(nameof(services)); 20 | services.ConfigureDynamicProxy(configure); 21 | services.AddAspectServiceContext(); 22 | return resolver = services.ToServiceContext().Build(); 23 | } 24 | 25 | public static T Resolve() 26 | { 27 | if (resolver == null) 28 | throw new ArgumentNullException(nameof(resolver), "调用此方法时必须先调用BuildServiceProvider!"); 29 | return resolver.Resolve(); 30 | } 31 | public static object Resolve(Type type) 32 | { 33 | if (resolver == null) 34 | throw new ArgumentNullException(nameof(resolver), "调用此方法时必须先调用BuildServiceProvider!"); 35 | return resolver.Resolve(type); 36 | } 37 | public static object Resolve(string typeName) 38 | { 39 | if (resolver == null) 40 | throw new ArgumentNullException(nameof(resolver), "调用此方法时必须先调用BuildServiceProvider!"); 41 | return resolver.Resolve(Type.GetType(typeName)); 42 | } 43 | public static List ResolveServices() 44 | { 45 | if (resolver == null) 46 | throw new ArgumentNullException(nameof(resolver), "调用此方法时必须先调用BuildServiceProvider!"); 47 | return resolver.GetServices().ToList(); 48 | } 49 | public static List ResolveServices(Func filter) 50 | { 51 | if (resolver == null) 52 | throw new ArgumentNullException(nameof(resolver), "调用此方法时必须先调用BuildServiceProvider!"); 53 | if (filter == null) filter = m => true; 54 | return ResolveServices().Where(filter).ToList(); 55 | } 56 | 57 | public static T GetDbContext(string tagName) where T:IDbContextCore 58 | { 59 | if (resolver == null) 60 | throw new ArgumentNullException(nameof(resolver), "调用此方法时必须先调用BuildServiceProvider!"); 61 | return (T) resolver.GetDbContext(tagName, typeof(T)); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IoC/AutofacContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using AspectCore.Configuration; 6 | using AspectCore.Extensions.Autofac; 7 | using Autofac; 8 | using Autofac.Core; 9 | using Autofac.Extensions.DependencyInjection; 10 | using Microsoft.Extensions.DependencyInjection; 11 | 12 | namespace Zxw.Framework.NetCore.IoC 13 | { 14 | /// 15 | /// Autofac IOC 容器 16 | /// 17 | public class AutofacContainer 18 | { 19 | private static ContainerBuilder _builder = new ContainerBuilder(); 20 | private static IContainer _container; 21 | private static string[] _otherAssembly; 22 | private static List _types = new List(); 23 | private static Dictionary _dicTypes = new Dictionary(); 24 | 25 | /// 26 | /// 注册程序集 27 | /// 28 | /// 程序集名称的集合 29 | public static void Register(params string[] assemblies) 30 | { 31 | _otherAssembly = assemblies; 32 | } 33 | 34 | /// 35 | /// 注册类型 36 | /// 37 | /// 38 | public static void Register(params Type[] types) 39 | { 40 | _types.AddRange(types.ToList()); 41 | } 42 | /// 43 | /// 注册程序集。 44 | /// 45 | /// 46 | /// 47 | public static void Register(string implementationAssemblyName, string interfaceAssemblyName) 48 | { 49 | var implementationAssembly = Assembly.Load(implementationAssemblyName); 50 | var interfaceAssembly = Assembly.Load(interfaceAssemblyName); 51 | var implementationTypes = 52 | implementationAssembly.DefinedTypes.Where(t => 53 | t.IsClass && !t.IsAbstract && !t.IsGenericType && !t.IsNested); 54 | foreach (var type in implementationTypes) 55 | { 56 | var interfaceTypeName = interfaceAssemblyName + ".I" + type.Name; 57 | var interfaceType = interfaceAssembly.GetType(interfaceTypeName); 58 | if (interfaceType.IsAssignableFrom(type)) 59 | { 60 | _dicTypes.Add(interfaceType, type); 61 | } 62 | } 63 | } 64 | /// 65 | /// 注册 66 | /// 67 | /// 68 | /// 69 | public static void Register() where TImplementation : TInterface 70 | { 71 | _dicTypes.Add(typeof(TInterface), typeof(TImplementation)); 72 | } 73 | 74 | /// 75 | /// 注册一个实体 76 | /// 77 | /// 78 | /// 79 | public static void Register(T instance) where T:class 80 | { 81 | _builder.RegisterInstance(instance).SingleInstance(); 82 | } 83 | 84 | /// 85 | /// 构建IOC容器,需在各种Register后调用。 86 | /// 87 | public static IServiceProvider Build(IServiceCollection services, Action config = null) 88 | { 89 | if (_otherAssembly != null) 90 | { 91 | foreach (var item in _otherAssembly) 92 | { 93 | _builder.RegisterAssemblyTypes(Assembly.Load(item)); 94 | } 95 | } 96 | 97 | if (_types != null) 98 | { 99 | foreach (var type in _types) 100 | { 101 | _builder.RegisterType(type); 102 | } 103 | } 104 | 105 | if (_dicTypes != null) 106 | { 107 | foreach (var dicType in _dicTypes) 108 | { 109 | _builder.RegisterType(dicType.Value).As(dicType.Key); 110 | } 111 | } 112 | 113 | _builder.Populate(services); 114 | _builder.RegisterDynamicProxy(config); 115 | _container = _builder.Build(); 116 | return new AutofacServiceProvider(_container); 117 | } 118 | 119 | /// 120 | /// Resolve an instance of the default requested type from the container 121 | /// 122 | /// 类型 123 | /// 124 | public static T Resolve() 125 | { 126 | return _container.Resolve(); 127 | } 128 | 129 | public static T Resolve(params Parameter[] parameters) 130 | { 131 | return _container.Resolve(parameters); 132 | } 133 | 134 | public static object Resolve(Type targetType) 135 | { 136 | return _container.Resolve(targetType); 137 | } 138 | 139 | public static object Resolve(Type targetType, params Parameter[] parameters) 140 | { 141 | return _container.Resolve(targetType, parameters); 142 | } 143 | } 144 | } -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IoC/IScopedDependency.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Zxw.Framework.NetCore.IoC 7 | { 8 | public interface IScopedDependency 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IoC/ISingletonDependency.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Zxw.Framework.NetCore.IoC 6 | { 7 | public interface ISingletonDependency 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IoC/ITransientDependency.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Zxw.Framework.NetCore.IoC 6 | { 7 | public interface ITransientDependency 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IoC/ServiceLifetimeDependencyInjectExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System; 3 | using System.Linq; 4 | using Zxw.Framework.NetCore.Extensions; 5 | using Zxw.Framework.NetCore.Helpers; 6 | 7 | namespace Zxw.Framework.NetCore.IoC 8 | { 9 | public static class ServiceLifetimeDependencyInjectExtensions 10 | { 11 | public static IServiceCollection RegisterServiceLifetimeDependencies(this IServiceCollection services) 12 | { 13 | RuntimeHelper.GetAllAssemblies().ToList().ForEach(a => 14 | { 15 | a.GetTypes().Where(t => t.IsClass).ToList().ForEach(t => 16 | { 17 | var serviceType = t.GetInterface($"I{t.Name}"); 18 | if ((serviceType??t).GetInterface(typeof(ISingletonDependency).Name)!=null) 19 | { 20 | if (serviceType != null) 21 | { 22 | services.AddSingleton(serviceType, t); 23 | } 24 | else 25 | { 26 | services.AddSingleton(t); 27 | } 28 | } 29 | else if ((serviceType ?? t).GetInterface(typeof(IScopedDependency).Name)!=null) 30 | { 31 | if (serviceType != null) 32 | { 33 | services.AddScoped(serviceType, t); 34 | } 35 | else 36 | { 37 | services.AddScoped(t); 38 | } 39 | } 40 | else if ((serviceType ?? t).GetInterface(typeof(ITransientDependency).Name)!=null) 41 | { 42 | if (serviceType != null) 43 | { 44 | services.AddTransient(serviceType, t); 45 | } 46 | else 47 | { 48 | services.AddTransient(t); 49 | } 50 | } 51 | }); 52 | }); 53 | return services; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/IoC/ServiceLocator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Zxw.Framework.NetCore.IoC 4 | { 5 | public static class ServiceLocator 6 | { 7 | internal static IServiceProvider Current { get; set; } 8 | 9 | public static T Resolve() 10 | { 11 | return (T)Current.GetService(typeof(T)); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Middlewares/ResponseTimeMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System.Diagnostics; 3 | using System.Threading.Tasks; 4 | using Zxw.Framework.NetCore.Helpers; 5 | 6 | namespace Zxw.Framework.NetCore.Middlewares 7 | { 8 | public class ResponseTimeMiddleware 9 | { 10 | // Handle to the next Middleware in the pipeline 11 | private readonly RequestDelegate _next; 12 | public ResponseTimeMiddleware(RequestDelegate next) 13 | { 14 | _next = next; 15 | } 16 | public Task InvokeAsync(HttpContext context) 17 | { 18 | // Start the Timer using Stopwatch 19 | var watch = new Stopwatch(); 20 | watch.Start(); 21 | context.Response.OnStarting(() => { 22 | // Stop the timer information and calculate the time 23 | watch.Stop(); 24 | var responseTimeForCompleteRequest = watch.ElapsedMilliseconds; 25 | // Add the Response time information in the Response headers. 26 | Log4NetHelper.WriteInfo(GetType(), $"\t{context.Request.Path.ToString()}\t{responseTimeForCompleteRequest}"); 27 | return Task.CompletedTask; 28 | }); 29 | // Call the next delegate/middleware in the pipeline 30 | return this._next(context); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Models/BaseModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Zxw.Framework.NetCore.Models 4 | { 5 | public interface IAggregateRoot 6 | { 7 | 8 | } 9 | 10 | public interface IBaseModel : IAggregateRoot 11 | { 12 | TKey Id { get; set; } 13 | } 14 | /// 15 | /// 所有数据表实体类都必须继承此类 16 | /// 17 | /// 18 | [Serializable] 19 | public abstract class BaseModel: IBaseModel 20 | { 21 | public abstract TKey Id { get; set; } 22 | } 23 | /// 24 | /// 所有数据库视图对应实体类必须继承此类 25 | /// 26 | [Serializable] 27 | public abstract class BaseViewModel : IAggregateRoot 28 | { 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Models/DbTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Zxw.Framework.NetCore.Models 5 | { 6 | [Serializable] 7 | public class DbTable 8 | { 9 | /// 10 | /// 表名 11 | /// 12 | public string TableName { get; set; } 13 | 14 | public string Alias { get; set; } 15 | 16 | /// 17 | /// 表说明 18 | /// 19 | public string TableComment { get; set; } 20 | /// 21 | /// 字段集合 22 | /// 23 | public virtual ICollection Columns { get; set; } = new List(); 24 | } 25 | [Serializable] 26 | public class DbTableColumn 27 | { 28 | public string TableName{get;set;} 29 | /// 30 | /// 字段名 31 | /// 32 | public string ColName { get; set; } 33 | public string Alias { get; set; } 34 | /// 35 | /// 是否自增 36 | /// 37 | public bool IsIdentity { get; set; } 38 | /// 39 | /// 是否主键 40 | /// 41 | public bool IsPrimaryKey { get; set; } 42 | /// 43 | /// 字段数据类型 44 | /// 45 | public string ColumnType { get; set; } 46 | /// 47 | /// 字段数据长度 48 | /// 49 | public long? ColumnLength { get; set; } 50 | /// 51 | /// 是否允许为空 52 | /// 53 | public bool IsNullable { get; set; } 54 | /// 55 | /// 默认值 56 | /// 57 | public string DefaultValue { get; set; } 58 | /// 59 | /// 字段说明 60 | /// 61 | public string Comments { get; set; } 62 | 63 | /// 64 | /// C#数据类型 65 | /// 66 | public string CSharpType { get; set; } 67 | /// 68 | /// 数据精度 69 | /// 70 | public int? DataPrecision { get; set; } 71 | /// 72 | /// 数据刻度 73 | /// 74 | public int? DataScale { get; set; } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Models/ExcutedResult.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.Models 2 | { 3 | public class ExcutedResult 4 | { 5 | public bool success { get; set; } 6 | 7 | public string msg { get; set; } 8 | 9 | public object rows { get; set; } 10 | 11 | public int? code { get; set; } 12 | 13 | public ExcutedResult(bool success, string msg, object rows, int? code = null) 14 | { 15 | this.success = success; 16 | this.msg = msg; 17 | this.rows = rows; 18 | this.code = code; 19 | } 20 | public static ExcutedResult SuccessResult(string msg = null) 21 | { 22 | return new ExcutedResult(true, msg, null); 23 | } 24 | public static ExcutedResult SuccessResult(object rows) 25 | { 26 | return new ExcutedResult(true, null, rows); 27 | } 28 | 29 | public static ExcutedResult FailedResult(string msg, int? code = null) 30 | { 31 | return new ExcutedResult(false, msg, null, code); 32 | } 33 | } 34 | 35 | public class PaginationResult : ExcutedResult 36 | { 37 | /// 38 | /// 总条数 39 | /// 40 | public int total { get; set; } 41 | /// 42 | /// 每页条数 43 | /// 44 | public int pageSize { get; set; } 45 | /// 46 | /// 当前页码 47 | /// 48 | public int pageIndex { get; set; } 49 | 50 | public PaginationResult(bool success, string msg, object rows) : base(success, msg, rows) 51 | { 52 | } 53 | 54 | public static PaginationResult PagedResult(object rows, int total, int size, int index) 55 | { 56 | return new PaginationResult(true, null, rows) 57 | { 58 | total = total, 59 | pageSize = size, 60 | pageIndex = index 61 | }; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Mvc/BaseController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Serialization; 4 | using Zxw.Framework.NetCore.Models; 5 | using Zxw.Framework.NetCore.Web; 6 | 7 | namespace Zxw.Framework.NetCore.Mvc 8 | { 9 | public abstract class BaseController:Controller 10 | { 11 | protected readonly IWebContext WebContext; 12 | public BaseController(IWebContext webContext) 13 | { 14 | WebContext = webContext; 15 | } 16 | 17 | protected IActionResult Json2(object content, string dateFormat = "yyyy-MM-dd HH:mm:ss") => Json(content, new JsonSerializerSettings() 18 | { 19 | DateFormatString = dateFormat, 20 | ContractResolver = new CamelCasePropertyNamesContractResolver() 21 | }); 22 | 23 | protected IActionResult SucceedJson(string msg) 24 | { 25 | return Json2(ExcutedResult.SuccessResult(msg: msg)); 26 | } 27 | protected IActionResult SucceedJson(object rows) 28 | { 29 | return Json2(ExcutedResult.SuccessResult(rows: rows)); 30 | } 31 | 32 | protected IActionResult FailedJson(string msg, int? code = null) 33 | { 34 | return Json2(ExcutedResult.FailedResult(msg, code)); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Options/CodeGenerateOption.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.Options 2 | { 3 | public class CodeGenerateOption 4 | { 5 | public virtual string OutputPath { get; set; } 6 | public virtual string ModelsNamespace { get; set; } 7 | public virtual string ViewModelsNamespace { get; set; } 8 | public virtual string ControllersNamespace { get; set; } 9 | public virtual string IRepositoriesNamespace { get; set; } 10 | public virtual string RepositoriesNamespace { get; set; } 11 | public virtual string IServicesNamespace { get; set; } 12 | public virtual string ServicesNamespace { get; set; } 13 | public bool IsPascalCase { get; set; } = true; 14 | public bool GenerateApiController { get; set; }= false; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Options/DbContextOption.cs: -------------------------------------------------------------------------------- 1 | namespace Zxw.Framework.NetCore.Options 2 | { 3 | public class DbContextOption 4 | { 5 | public string TagName { get; set; } 6 | /// 7 | /// 数据库连接字符串 8 | /// 9 | public string ConnectionString { get; set; } 10 | /// 11 | /// 实体程序集名称 12 | /// 13 | public string ModelAssemblyName { get; set; } 14 | /// 15 | /// 是否在控制台输出SQL语句,默认开启 16 | /// 17 | public bool IsOutputSql { get; set; } = true; 18 | /// 19 | /// 是否开启跟踪 20 | /// 21 | public bool EnableNoTracking { get; set; } = true; 22 | /// 23 | /// 是否开启LazyLoadingProxy 24 | /// 25 | public bool EnableLazyLoadingProxy { get; set; } = true; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Repositories/BaseRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Common; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Threading.Tasks; 7 | using Microsoft.EntityFrameworkCore; 8 | using Zxw.Framework.NetCore.Extensions; 9 | using Zxw.Framework.NetCore.IDbContext; 10 | using Zxw.Framework.NetCore.Models; 11 | 12 | namespace Zxw.Framework.NetCore.Repositories 13 | { 14 | public abstract class BaseRepository:IRepository where T : BaseModel, new() 15 | { 16 | protected readonly IDbContextCore DbContext; 17 | protected readonly ISqlOperatorUtility SqlOperatorUtility; 18 | 19 | protected DbSet DbSet => DbContext.GetDbSet(); 20 | 21 | protected BaseRepository(IDbContextCore dbContext, ISqlOperatorUtility sqlOperator) 22 | { 23 | DbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext)); 24 | DbContext.EnsureCreated(); 25 | 26 | SqlOperatorUtility = sqlOperator; 27 | } 28 | 29 | #region Insert 30 | 31 | public virtual int Add(T entity) 32 | { 33 | return DbContext.Add(entity); 34 | } 35 | 36 | public virtual async Task AddAsync(T entity) 37 | { 38 | return await DbContext.AddAsync(entity); 39 | } 40 | 41 | public virtual int AddRange(ICollection entities) 42 | { 43 | return DbContext.AddRange(entities); 44 | } 45 | 46 | public virtual async Task AddRangeAsync(ICollection entities) 47 | { 48 | return await DbContext.AddRangeAsync(entities); 49 | } 50 | 51 | public virtual void BulkInsert(IList entities, string destinationTableName = null) 52 | { 53 | DbContext.BulkInsert(entities, destinationTableName); 54 | } 55 | 56 | public int AddBySql(string sql) 57 | { 58 | return DbContext.ExecuteSqlWithNonQuery(sql); 59 | } 60 | 61 | #endregion 62 | 63 | #region Update 64 | 65 | public int DeleteBySql(string sql) 66 | { 67 | return SqlOperatorUtility.ExecuteSqlCommand(sql); 68 | } 69 | 70 | public virtual int Edit(T entity) 71 | { 72 | return DbContext.Edit(entity); 73 | } 74 | 75 | public virtual int EditRange(ICollection entities) 76 | { 77 | return DbContext.EditRange(entities); 78 | } 79 | /// 80 | /// update query datas by columns. 81 | /// 82 | /// 83 | /// 84 | /// 85 | /// 86 | public virtual int BatchUpdate(Expression> @where, Expression> updateExp) 87 | { 88 | return DbContext.Update(where, updateExp); 89 | } 90 | 91 | public virtual async Task BatchUpdateAsync(Expression> @where, Expression> updateExp) 92 | { 93 | return await DbContext.UpdateAsync(@where, updateExp); 94 | } 95 | public virtual int Update(T model, params string[] updateColumns) 96 | { 97 | DbContext.Update(model, updateColumns); 98 | return DbContext.SaveChanges(); 99 | } 100 | 101 | public virtual int Update(Expression> @where, Expression> updateFactory) 102 | { 103 | return DbContext.Update(where, updateFactory); 104 | } 105 | 106 | public virtual async Task UpdateAsync(Expression> @where, Expression> updateFactory) 107 | { 108 | return await DbContext.UpdateAsync(where, updateFactory); 109 | } 110 | 111 | public int UpdateBySql(string sql) 112 | { 113 | return SqlOperatorUtility.ExecuteSqlCommand(sql); 114 | } 115 | 116 | #endregion 117 | 118 | #region Delete 119 | 120 | public virtual int Delete(TKey key) 121 | { 122 | return DbContext.Delete(key); 123 | } 124 | 125 | public virtual int Delete(Expression> @where) 126 | { 127 | return DbContext.Delete(where); 128 | } 129 | 130 | public virtual async Task DeleteAsync(Expression> @where) 131 | { 132 | return await DbContext.DeleteAsync(where); 133 | } 134 | 135 | 136 | #endregion 137 | 138 | #region Query 139 | 140 | public virtual int Count(Expression> @where = null) 141 | { 142 | return DbContext.Count(where); 143 | } 144 | 145 | public virtual async Task CountAsync(Expression> @where = null) 146 | { 147 | return await DbContext.CountAsync(where); 148 | } 149 | 150 | 151 | public virtual bool Exist(Expression> @where = null) 152 | { 153 | return DbContext.Exist(where); 154 | } 155 | 156 | public virtual async Task ExistAsync(Expression> @where = null) 157 | { 158 | return await DbContext.ExistAsync(where); 159 | } 160 | 161 | /// 162 | /// 根据主键获取实体。建议:如需使用Include和ThenInclude请重载此方法。 163 | /// 164 | /// 165 | /// 166 | public virtual T GetSingle(TKey key) 167 | { 168 | return DbContext.Find(key); 169 | } 170 | 171 | public T GetSingle(TKey key, Func, IQueryable> includeFunc) 172 | { 173 | if (includeFunc == null) return GetSingle(key); 174 | return includeFunc(DbSet.Where(m => m.Id.Equal(key))).AsNoTracking().FirstOrDefault(); 175 | } 176 | 177 | /// 178 | /// 根据主键获取实体。建议:如需使用Include和ThenInclude请重载此方法。 179 | /// 180 | /// 181 | /// 182 | public virtual async Task GetSingleAsync(TKey key) 183 | { 184 | return await DbContext.FindAsync(key); 185 | } 186 | 187 | /// 188 | /// 获取单个实体。建议:如需使用Include和ThenInclude请重载此方法。 189 | /// 190 | public virtual T GetSingleOrDefault(Expression> @where = null) 191 | { 192 | return DbContext.GetSingleOrDefault(@where); 193 | } 194 | 195 | /// 196 | /// 获取单个实体。建议:如需使用Include和ThenInclude请重载此方法。 197 | /// 198 | public virtual async Task GetSingleOrDefaultAsync(Expression> @where = null) 199 | { 200 | return await DbContext.GetSingleOrDefaultAsync(where); 201 | } 202 | 203 | /// 204 | /// 获取实体列表。建议:如需使用Include和ThenInclude请重载此方法。 205 | /// 206 | public virtual IList Get(Expression> @where = null) 207 | { 208 | return DbContext.Get(where).ToList(); 209 | } 210 | 211 | /// 212 | /// 获取实体列表。建议:如需使用Include和ThenInclude请重载此方法。 213 | /// 214 | public virtual async Task> GetAsync(Expression> @where = null) 215 | { 216 | return await DbContext.Get(where).ToListAsync(); 217 | } 218 | 219 | /// 220 | /// 分页获取实体列表。建议:如需使用Include和ThenInclude请重载此方法。 221 | /// 222 | public virtual IEnumerable GetByPagination(Expression> @where, int pageSize, int pageIndex, bool asc = true, params Expression>[] @orderby) 223 | { 224 | var filter = DbContext.Get(where); 225 | if (orderby != null) 226 | { 227 | foreach (var func in orderby) 228 | { 229 | filter = asc ? filter.OrderBy(func).AsQueryable() : filter.OrderByDescending(func).AsQueryable(); 230 | } 231 | } 232 | return filter.Skip(pageSize * (pageIndex - 1)).Take(pageSize); 233 | } 234 | 235 | public List GetBySql(string sql) 236 | { 237 | return SqlOperatorUtility.SqlQuery(sql).ToList(); 238 | } 239 | 240 | public List GetViews(string sql) 241 | { 242 | var list = SqlOperatorUtility.SqlQuery(sql).ToList(); 243 | return list; 244 | } 245 | 246 | public List GetViews(string viewName, Func @where) 247 | { 248 | var list = SqlOperatorUtility.SqlQuery($"select * from {viewName}").ToList(); 249 | if (where != null) 250 | { 251 | return list.Where(where).ToList(); 252 | } 253 | 254 | return list; 255 | } 256 | 257 | public virtual PaginationResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize, 258 | params DbParameter[] parameters) 259 | { 260 | return DbContext.SqlQueryByPagination(sql, orderBys, pageIndex, pageSize, parameters); 261 | } 262 | 263 | public virtual PaginationResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize) where TView : class 264 | { 265 | return DbContext.SqlQueryByPagination(sql, orderBys, pageIndex, pageSize); 266 | } 267 | 268 | #endregion 269 | 270 | public void Dispose() 271 | { 272 | DbContext?.Dispose(); 273 | } 274 | } 275 | } 276 | 277 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Repositories/IRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Common; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Threading.Tasks; 7 | using Zxw.Framework.NetCore.Attributes; 8 | using Zxw.Framework.NetCore.IoC; 9 | using Zxw.Framework.NetCore.Models; 10 | 11 | namespace Zxw.Framework.NetCore.Repositories 12 | { 13 | [FromDbContextFactoryInterceptor] 14 | public interface IRepository: ITransientDependency, IDisposable where T : class, IBaseModel ,new() 15 | { 16 | #region Insert 17 | 18 | int Add(T entity); 19 | Task AddAsync(T entity); 20 | int AddRange(ICollection entities); 21 | Task AddRangeAsync(ICollection entities); 22 | void BulkInsert(IList entities, string destinationTableName = null); 23 | int AddBySql(string sql); 24 | 25 | #endregion 26 | 27 | #region Delete 28 | 29 | int Delete(TKey key); 30 | int Delete(Expression> @where); 31 | Task DeleteAsync(Expression> @where); 32 | int DeleteBySql(string sql); 33 | #endregion 34 | 35 | #region Update 36 | 37 | int Edit(T entity); 38 | int EditRange(ICollection entities); 39 | int BatchUpdate(Expression> @where, Expression> updateExp); 40 | Task BatchUpdateAsync(Expression> @where, Expression> updateExp); 41 | int Update(T model, params string[] updateColumns); 42 | int Update(Expression> @where, Expression> updateFactory); 43 | Task UpdateAsync(Expression> @where, Expression> updateFactory); 44 | int UpdateBySql(string sql); 45 | 46 | #endregion 47 | 48 | #region Query 49 | 50 | int Count(Expression> @where = null); 51 | Task CountAsync(Expression> @where = null); 52 | bool Exist(Expression> @where = null); 53 | Task ExistAsync(Expression> @where = null); 54 | T GetSingle(TKey key); 55 | T GetSingle(TKey key, Func, IQueryable> includeFunc); 56 | Task GetSingleAsync(TKey key); 57 | T GetSingleOrDefault(Expression> @where = null); 58 | Task GetSingleOrDefaultAsync(Expression> @where = null); 59 | IList Get(Expression> @where = null); 60 | Task> GetAsync(Expression> @where = null); 61 | IEnumerable GetByPagination(Expression> @where, int pageSize, int pageIndex, bool asc = true, 62 | params Expression>[] @orderby); 63 | 64 | List GetBySql(string sql); 65 | 66 | List GetViews(string sql); 67 | List GetViews(string viewName, Func where); 68 | 69 | PaginationResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize, 70 | params DbParameter[] parameters); 71 | PaginationResult SqlQueryByPagination(string sql, string[] orderBys, int pageIndex, int pageSize) 72 | where TView : class; 73 | #endregion 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Repositories/ServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Microsoft.Extensions.DependencyInjection.Extensions; 9 | using Zxw.Framework.NetCore.Models; 10 | 11 | namespace Zxw.Framework.NetCore.Repositories 12 | { 13 | public static class ServiceExtensions 14 | { 15 | public static IServiceCollection RegisterDefaultRepositories(this IServiceCollection services) where T:DbContext,new() 16 | { 17 | var assembly = Assembly.GetExecutingAssembly(); 18 | var list = assembly.GetTypes().Where(t => t.GetCustomAttributes() 19 | .Any(a => a.ContextType == typeof(T)) 20 | && !t.GetCustomAttributes().Any() && 21 | !t.FullName.Contains("Migrations")).ToList(); 22 | if (list.Any()) 23 | { 24 | foreach (var type in list) 25 | { 26 | var pkType = GetPrimaryKeyType(type); 27 | var implType = GetRepositoryType(type, pkType); 28 | if (pkType != null) 29 | { 30 | services.TryAddScoped(typeof(IRepository<,>).MakeGenericType(type, pkType), implType); 31 | } 32 | } 33 | } 34 | return services; 35 | } 36 | 37 | private static Type GetRepositoryType(Type entityType, Type primaryKeyType) 38 | { 39 | return typeof(BaseRepository<,>).MakeGenericType(entityType, primaryKeyType); 40 | } 41 | 42 | private static Type GetPrimaryKeyType(Type entityType) 43 | { 44 | foreach (var interfaceType in entityType.GetTypeInfo().GetInterfaces()) 45 | { 46 | if (interfaceType.GetTypeInfo().IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(BaseModel<>)) 47 | { 48 | return interfaceType.GenericTypeArguments[0]; 49 | } 50 | } 51 | 52 | return null; 53 | } 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Services/BaseService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Threading.Tasks; 5 | using Zxw.Framework.NetCore.Models; 6 | using Zxw.Framework.NetCore.Repositories; 7 | 8 | namespace Zxw.Framework.NetCore.Services 9 | { 10 | public abstract class BaseService:IService where T:class, IBaseModel, new() 11 | { 12 | public IRepository Repository { get; set; } 13 | protected BaseService(IRepository repository) 14 | { 15 | Repository = repository; 16 | } 17 | 18 | public virtual int Add(T model) 19 | { 20 | return Repository.Add(model); 21 | } 22 | 23 | public virtual async Task AddAsync(T entity) 24 | { 25 | return await Repository.AddAsync(entity); 26 | } 27 | 28 | public virtual int AddRange(IList models) 29 | { 30 | return Repository.AddRange(models); 31 | } 32 | 33 | public virtual async Task AddRangeAsync(IList entities) 34 | { 35 | return await Repository.AddRangeAsync(entities); 36 | } 37 | 38 | public virtual void BulkInsert(IList entities) 39 | { 40 | Repository.BulkInsert(entities, typeof(T).Name); 41 | } 42 | 43 | public virtual int Edit(T model) 44 | { 45 | return Repository.Edit(model); 46 | } 47 | 48 | public virtual int EditRange(ICollection entities) 49 | { 50 | return Repository.EditRange(entities); 51 | } 52 | 53 | public virtual int BatchUpdate(Expression> @where, Expression> updateExp) 54 | { 55 | return Repository.BatchUpdate(where, updateExp); 56 | } 57 | 58 | public virtual async Task BatchUpdateAsync(Expression> @where, Expression> updateExp) 59 | { 60 | return await Repository.BatchUpdateAsync(where, updateExp); 61 | } 62 | 63 | public virtual int Update(T model, params string[] updateColumns) 64 | { 65 | return Repository.Update(model, updateColumns); 66 | } 67 | 68 | public virtual int Update(Expression> @where, Expression> updateFactory) 69 | { 70 | return Repository.Update(where, updateFactory); 71 | } 72 | 73 | public virtual async Task UpdateAsync(Expression> @where, Expression> updateFactory) 74 | { 75 | return await Repository.UpdateAsync(where, updateFactory); 76 | } 77 | 78 | public virtual int Delete(TKey key) 79 | { 80 | return Repository.Delete(key); 81 | } 82 | 83 | public virtual int Delete(Expression> @where) 84 | { 85 | return Repository.Delete(where); 86 | } 87 | 88 | public virtual async Task DeleteAsync(Expression> @where) 89 | { 90 | return await Repository.DeleteAsync(where); 91 | } 92 | 93 | public virtual int Count(Expression> @where = null) 94 | { 95 | return Repository.Count(where); 96 | } 97 | 98 | public virtual async Task CountAsync(Expression> @where = null) 99 | { 100 | return await Repository.CountAsync(where); 101 | } 102 | 103 | public virtual bool Exist(Expression> @where = null) 104 | { 105 | return Repository.Exist(where); 106 | } 107 | 108 | public virtual async Task ExistAsync(Expression> @where = null) 109 | { 110 | return await Repository.ExistAsync(where); 111 | } 112 | 113 | public virtual T GetSingle(TKey key) 114 | { 115 | return Repository.GetSingle(key); 116 | } 117 | 118 | public virtual async Task GetSingleAsync(TKey key) 119 | { 120 | return await Repository.GetSingleAsync(key); 121 | } 122 | 123 | public virtual T GetSingleOrDefault(Expression> @where = null) 124 | { 125 | return Repository.GetSingleOrDefault(where); 126 | } 127 | 128 | public virtual async Task GetSingleOrDefaultAsync(Expression> @where = null) 129 | { 130 | return await Repository.GetSingleOrDefaultAsync(where); 131 | } 132 | 133 | public virtual IList Get(Expression> @where = null) 134 | { 135 | return Repository.Get(where); 136 | } 137 | 138 | public virtual async Task> GetAsync(Expression> @where = null) 139 | { 140 | return await Repository.GetAsync(where); 141 | } 142 | 143 | public virtual IEnumerable GetByPagination(Expression> @where, int pageSize, int pageIndex, bool asc = true, params Expression>[] @orderby) 144 | { 145 | return Repository.GetByPagination(where, pageSize, pageIndex, asc, orderby); 146 | } 147 | 148 | public void Dispose() 149 | { 150 | Repository?.Dispose(); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Services/IServices.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Threading.Tasks; 6 | using Zxw.Framework.NetCore.IoC; 7 | using Zxw.Framework.NetCore.Models; 8 | 9 | namespace Zxw.Framework.NetCore.Services 10 | { 11 | public interface IService: ITransientDependency, IDisposable where T:IBaseModel 12 | { 13 | #region Insert 14 | 15 | int Add(T model); 16 | Task AddAsync(T entity); 17 | int AddRange(IList models); 18 | Task AddRangeAsync(IList entities); 19 | void BulkInsert(IList entities); 20 | 21 | #endregion 22 | 23 | #region Update 24 | 25 | int Edit(T entity); 26 | int EditRange(ICollection entities); 27 | int BatchUpdate(Expression> @where, Expression> updateExp); 28 | Task BatchUpdateAsync(Expression> @where, Expression> updateExp); 29 | int Update(T model, params string[] updateColumns); 30 | int Update(Expression> @where, Expression> updateFactory); 31 | Task UpdateAsync(Expression> @where, Expression> updateFactory); 32 | 33 | #endregion 34 | 35 | #region Delete 36 | 37 | int Delete(TKey key); 38 | int Delete(Expression> @where); 39 | Task DeleteAsync(Expression> @where); 40 | 41 | #endregion 42 | 43 | #region Query 44 | 45 | int Count(Expression> @where = null); 46 | Task CountAsync(Expression> @where = null); 47 | bool Exist(Expression> @where = null); 48 | Task ExistAsync(Expression> @where = null); 49 | T GetSingle(TKey key); 50 | Task GetSingleAsync(TKey key); 51 | T GetSingleOrDefault(Expression> @where = null); 52 | Task GetSingleOrDefaultAsync(Expression> @where = null); 53 | IList Get(Expression> @where = null); 54 | Task> GetAsync(Expression> @where = null); 55 | IEnumerable GetByPagination(Expression> @where, int pageSize, int pageIndex, bool asc = true, 56 | params Expression>[] @orderby); 57 | #endregion 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Web/IWebContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Zxw.Framework.NetCore.Extensions; 3 | using Zxw.Framework.NetCore.IoC; 4 | 5 | namespace Zxw.Framework.NetCore.Web 6 | { 7 | public interface IWebContext: ISingletonDependency 8 | { 9 | HttpContext CoreContext { get; } 10 | T GetService(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Web/WebContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System; 3 | using Zxw.Framework.NetCore.Extensions; 4 | 5 | namespace Zxw.Framework.NetCore.Web 6 | { 7 | public class WebContext : IWebContext 8 | { 9 | public HttpContext CoreContext { get; } 10 | 11 | public WebContext(IHttpContextAccessor accessor) 12 | { 13 | CoreContext = accessor?.HttpContext ?? throw new ArgumentNullException($"参数{nameof(accessor)}为null,请先在Startup.cs文件中的ConfigServices方法里使用AddHttpContextAccessor注入IHttpContextAccessor对象。"); 14 | } 15 | 16 | public virtual T GetService() 17 | { 18 | return CoreContext.GetService(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Zxw.Framework.NetCore/Zxw.Framework.NetCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0;net7.0; 5 | victor.tzeng 6 | 7 | 6.1.0.0 8 | 6.1.0.0 9 | 6.1.0.0 10 | true 11 | victor.tzeng@outlook.com 12 | https://github.com/VictorTzeng/Zxw.Framework.NetCore 13 | 基于EF Core的Code First模式的DotNetCore快速开发框架 14 | 兼容.net7.0,并移除对MongoDB的支持,如遇任何问题请至https://github.com/VictorTzeng/Zxw.Framework.NetCore/issues反馈,感谢支持。 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | all 75 | runtime; build; native; contentfiles; analyzers; buildtransitive 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | all 85 | runtime; build; native; contentfiles; analyzers; buildtransitive 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Zxw.Framework.UnitTest/DbContextUnitTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using Zxw.Framework.NetCore.CodeGenerator; 7 | using Zxw.Framework.NetCore.DbContextCore; 8 | using Zxw.Framework.NetCore.IDbContext; 9 | using Zxw.Framework.NetCore.Options; 10 | using Zxw.Framework.UnitTest.TestModels; 11 | using Zxw.Framework.NetCore.Extensions; 12 | using Zxw.Framework.NetCore.IoC; 13 | using System.Diagnostics; 14 | 15 | namespace Zxw.Framework.UnitTest 16 | { 17 | [TestClass] 18 | public class DbContextUnitTest 19 | { 20 | [TestMethod] 21 | public void TestCompileQuery() 22 | { 23 | BuildServiceForSqlServer(); 24 | var dbContext = ServiceLocator.Resolve(); 25 | var watch = new Stopwatch(); 26 | watch.Start(); 27 | dbContext.Get(m => m.Active); 28 | watch.Stop(); 29 | Console.WriteLine($"Get --> {watch.ElapsedMilliseconds} ms."); 30 | watch.Restart(); 31 | dbContext.GetByCompileQuery(m => m.Active); 32 | watch.Stop(); 33 | Console.WriteLine($"GetByCompileQuery --> {watch.ElapsedMilliseconds} ms."); 34 | } 35 | 36 | #region public methods 37 | 38 | public void BuildServiceForSqlServer() 39 | { 40 | IServiceCollection services = new ServiceCollection(); 41 | 42 | //在这里注册EF上下文 43 | services = RegisterSqlServerContext(services); 44 | 45 | services.AddOptions(); 46 | services.BuildAspectCoreServiceProvider(); 47 | } 48 | 49 | /// 50 | /// 注册SQLServer上下文 51 | /// 52 | /// 53 | /// 54 | public IServiceCollection RegisterSqlServerContext(IServiceCollection services) 55 | { 56 | services.Configure(options => 57 | { 58 | options.ConnectionString = 59 | "initial catalog=NetCoreDemo;data source=.;password=admin123!@#;User id=sa;MultipleActiveResultSets=True;"; 60 | options.ModelAssemblyName = "Zxw.Framework.UnitTest"; 61 | options.IsOutputSql = false; 62 | }); 63 | services.AddTransient(); //注入EF上下文 64 | return services; 65 | } 66 | #endregion 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Zxw.Framework.UnitTest/TestModels/SysMenu.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Zxw.Framework.NetCore.DbContextCore; 7 | using Zxw.Framework.NetCore.Models; 8 | 9 | namespace Zxw.Framework.UnitTest.TestModels 10 | { 11 | [Serializable] 12 | [DbContext(typeof(SqlServerDbContext))] 13 | [Table("SysMenu")] 14 | public class SysMenu:BaseModel 15 | { 16 | [Key] 17 | [Column("SysMenuId")] 18 | [MaxLength(36)] 19 | public override string Id { get; set; } 20 | 21 | [MaxLength(255)] 22 | public string ParentId { get; set; } = String.Empty; 23 | 24 | [MaxLength(255)] 25 | public string MenuPath { get; set; } 26 | 27 | [Required] 28 | [MaxLength(20)] 29 | public string MenuName { get; set; } 30 | 31 | [MaxLength(50)] 32 | public string MenuIcon { get; set; } 33 | 34 | [Required] 35 | [MaxLength(100)] 36 | public string Identity { get; set; } 37 | 38 | [Required] 39 | [MaxLength(200)] 40 | public string RouteUrl { get; set; } 41 | 42 | public bool Visible { get; set; } = true; 43 | 44 | public bool Active { get; set; } = true; 45 | 46 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 47 | public int SortIndex { get; set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Zxw.Framework.UnitTest/Zxw.Framework.UnitTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # ASP.NET Core (.NET Framework) 2 | # Build and test ASP.NET Core projects targeting the full .NET Framework. 3 | # Add steps that publish symbols, save build artifacts, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: 'windows-latest' 11 | 12 | variables: 13 | solution: '**/*.sln' 14 | buildPlatform: 'Any CPU' 15 | buildConfiguration: 'Release' 16 | 17 | steps: 18 | - task: NuGetToolInstaller@1 19 | 20 | - task: NuGetCommand@2 21 | inputs: 22 | restoreSolution: '$(solution)' 23 | 24 | - task: VSBuild@1 25 | inputs: 26 | solution: '$(solution)' 27 | msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"' 28 | platform: '$(buildPlatform)' 29 | configuration: '$(buildConfiguration)' 30 | 31 | - task: VSTest@2 32 | inputs: 33 | platform: '$(buildPlatform)' 34 | configuration: '$(buildConfiguration)' 35 | --------------------------------------------------------------------------------