使用Abp.Io做开发已经有一段时间了,由于使用的是模块化开发模式,项目比较多,因而不能再像以前那样,把全部项目都放到一个解决方案里了。这时候,就需要使用BaGet搭建一个本地源来存储并引用模块,虽然可以使用PowerShell脚本来对模块进行打包并发布,但还是有点麻烦,主要的痛点是需要更新项目中引用模块的版本号,挺烦人的。经过一段时间摸索,发现只要发布一次,通过覆盖本地缓存包的方式,就可以很轻松的更新dll了。

搭建BaGet

要搭建BaGet作为本地源比较简单,在GitHub下载一个发布包,然后在Win10里运行BaGet.exe就行了。笔者将BaGet设置为了Windows Terminal的一个菜单项,直接选择菜单打开就行了,非常方便。
BaGet的主要设置(appsettings.json):

  "ApiKey": "1q2w3E", "Urls": "http://*:1234","PackageDeletionBehavior": "HardDelete","AllowPackageOverwrites": true,

说明

  • ApiKey:这个是推送包时需要使用到的相当于密码的Key
  • Urls:BaGet的访问地址,笔者将地址设置为了http://localhost:1234
  • PackageDeletionBehavior:这个建议设置为HardDelete,使用硬删除方式,而不是软删除方式
  • AllowPackageOverwrites:这里设置为true表示可以覆盖包,这对于不更改版本号直接重新发布包相当有用

Windows Terminal菜单项设置:

......{"startingDirectory": "D:\\Workspace\\BaGet\\","colorScheme": "Dark+","commandline": "D:\\Workspace\\BaGet\\BaGet.exe","guid": "{29b0dc58-8a68-4f2e-a260-4f73a91cf99d}","name": "BaGet"},
......

具体的菜单项设置,可参考文档Windows 终端中的配置文件设置。
以上配置中,要注意的是必须配置startingDirectory来指定运行路径,不然会因找不到appsettings.json文件而运行失败。

模块的编译和发布

编译

在Abp框架的源代码中,提供了很好的源代码编译和发布脚本,只需要稍作修改就可以应用到自己的项目中。使用Git clone目录将Abp框架先下载到本地。打开项目根目录的的build文件夹,会看到4个Powershell脚本。这4个脚本是用来编译项目用的,我们需要做的是把这4个文件复制到自己的项目中,
然后调整common.ps1文件。
打开common.ps1文件,会看到以下代码:

$full = $args[0]# COMMON PATHS $rootFolder = (Get-Item -Path "./" -Verbose).FullName# List of solutions used only in development mode
$solutionPaths = @("../framework","../modules/users","../modules/permission-management","../modules/setting-management","../modules/feature-management","../modules/identity","../modules/identityserver","../modules/tenant-management","../modules/audit-logging","../modules/background-jobs","../modules/account")if ($full -eq "-f")
{# List of additional solutions required for full build$solutionPaths += ("../modules/client-simulation","../modules/virtual-file-explorer","../modules/docs","../modules/blogging","../templates/module/aspnet-core","../templates/app/aspnet-core","../abp_io/AbpIoLocalization")
}else{ Write-host ""Write-host ":::::::::::::: !!! You are in development mode !!! ::::::::::::::" -ForegroundColor red -BackgroundColor  yellowWrite-host ""
} 

代码中,在变量$solutionPaths定义了要编译的解决方案的路径,把自己项目中需要编译的模块写到定义中,就可对项目模块进行编译了。后面的if语句可以整个删除,哪只是附加的解决方案。文件修改好以后,就可执行build-all.ps1build-all-release.ps1来生产模块了。

发布

nupkg文件夹包含了发布包所需的3个脚本。其中的common.ps1文件和编译的common.ps1文件类似,用来定义解决方案和项目路径,代码如下:

# Paths
$packFolder = (Get-Item -Path "./" -Verbose).FullName
$rootFolder = Join-Path $packFolder "../"# List of solutions
$solutions = ("framework","modules/account","modules/audit-logging","modules/background-jobs","modules/blogging","modules/client-simulation","modules/docs","modules/feature-management","modules/identity","modules/identityserver","modules/permission-management","modules/setting-management","modules/tenant-management","modules/users","modules/virtual-file-explorer","modules/blob-storing-database"
)# List of projects
$projects = (# framework"framework/src/Volo.Abp.ApiVersioning.Abstractions","framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer","framework/src/Volo.Abp.AspNetCore.Authentication.OAuth","framework/src/Volo.Abp.AspNetCore","framework/src/Volo.Abp.AspNetCore.MultiTenancy","framework/src/Volo.Abp.AspNetCore.Mvc.Client","framework/src/Volo.Abp.AspNetCore.Mvc.Contracts","framework/src/Volo.Abp.AspNetCore.Mvc","framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap","framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling","framework/src/Volo.Abp.AspNetCore.Mvc.UI","framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy","framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages","framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic","framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared","framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets","framework/src/Volo.Abp.AspNetCore.Serilog","framework/src/Volo.Abp.AspNetCore.SignalR","framework/src/Volo.Abp.AspNetCore.TestBase","framework/src/Volo.Abp.Auditing","framework/src/Volo.Abp.Authorization","framework/src/Volo.Abp.Autofac","framework/src/Volo.Abp.AutoMapper","framework/src/Volo.Abp.BackgroundJobs.Abstractions","framework/src/Volo.Abp.BackgroundJobs","framework/src/Volo.Abp.BackgroundJobs.HangFire","framework/src/Volo.Abp.BackgroundJobs.RabbitMQ","framework/src/Volo.Abp.BackgroundJobs.Quartz","framework/src/Volo.Abp.BackgroundWorkers","framework/src/Volo.Abp.BackgroundWorkers.Quartz","framework/src/Volo.Abp.BlobStoring","framework/src/Volo.Abp.BlobStoring.FileSystem","framework/src/Volo.Abp.BlobStoring.Aliyun","framework/src/Volo.Abp.BlobStoring.Azure","framework/src/Volo.Abp.BlobStoring.Minio","framework/src/Volo.Abp.BlobStoring.Aws","framework/src/Volo.Abp.Caching","framework/src/Volo.Abp.Caching.StackExchangeRedis","framework/src/Volo.Abp.Castle.Core","framework/src/Volo.Abp.Cli.Core","framework/src/Volo.Abp.Cli","framework/src/Volo.Abp.Core","framework/src/Volo.Abp","framework/src/Volo.Abp.Dapper","framework/src/Volo.Abp.Data","framework/src/Volo.Abp.Ddd.Application","framework/src/Volo.Abp.Ddd.Application.Contracts","framework/src/Volo.Abp.Ddd.Domain","framework/src/Volo.Abp.Emailing","framework/src/Volo.Abp.EntityFrameworkCore","framework/src/Volo.Abp.EntityFrameworkCore.MySQL","framework/src/Volo.Abp.EntityFrameworkCore.Oracle","framework/src/Volo.Abp.EntityFrameworkCore.Oracle.Devart","framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql","framework/src/Volo.Abp.EntityFrameworkCore.Sqlite","framework/src/Volo.Abp.EntityFrameworkCore.SqlServer","framework/src/Volo.Abp.EventBus","framework/src/Volo.Abp.EventBus.RabbitMQ","framework/src/Volo.Abp.Features","framework/src/Volo.Abp.FluentValidation","framework/src/Volo.Abp.Guids","framework/src/Volo.Abp.HangFire","framework/src/Volo.Abp.Http.Abstractions","framework/src/Volo.Abp.Http.Client","framework/src/Volo.Abp.Http.Client.IdentityModel","framework/src/Volo.Abp.Http.Client.IdentityModel.Web","framework/src/Volo.Abp.Http","framework/src/Volo.Abp.IdentityModel","framework/src/Volo.Abp.Json","framework/src/Volo.Abp.Ldap","framework/src/Volo.Abp.Localization.Abstractions","framework/src/Volo.Abp.MailKit","framework/src/Volo.Abp.Localization","framework/src/Volo.Abp.MemoryDb","framework/src/Volo.Abp.MongoDB","framework/src/Volo.Abp.MultiTenancy","framework/src/Volo.Abp.Minify","framework/src/Volo.Abp.ObjectExtending","framework/src/Volo.Abp.ObjectMapping","framework/src/Volo.Abp.Quartz","framework/src/Volo.Abp.RabbitMQ","framework/src/Volo.Abp.Security","framework/src/Volo.Abp.Serialization","framework/src/Volo.Abp.Settings","framework/src/Volo.Abp.Sms","framework/src/Volo.Abp.Specifications","framework/src/Volo.Abp.TestBase","framework/src/Volo.Abp.TextTemplating","framework/src/Volo.Abp.Threading","framework/src/Volo.Abp.Timing","framework/src/Volo.Abp.UI","framework/src/Volo.Abp.UI.Navigation","framework/src/Volo.Abp.Uow","framework/src/Volo.Abp.Validation.Abstractions","framework/src/Volo.Abp.Validation","framework/src/Volo.Abp.VirtualFileSystem",# modules/account"modules/account/src/Volo.Abp.Account.Application.Contracts","modules/account/src/Volo.Abp.Account.Application","modules/account/src/Volo.Abp.Account.HttpApi.Client","modules/account/src/Volo.Abp.Account.HttpApi","modules/account/src/Volo.Abp.Account.Web","modules/account/src/Volo.Abp.Account.Web.IdentityServer",# modules/audit-logging"modules/audit-logging/src/Volo.Abp.AuditLogging.Domain","modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared","modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore","modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB",# modules/background-jobs"modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain","modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain.Shared","modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore","modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB",# modules/blogging"modules/blogging/src/Volo.Blogging.Application.Contracts.Shared","modules/blogging/src/Volo.Blogging.Application.Contracts","modules/blogging/src/Volo.Blogging.Application","modules/blogging/src/Volo.Blogging.Domain","modules/blogging/src/Volo.Blogging.Domain.Shared","modules/blogging/src/Volo.Blogging.EntityFrameworkCore","modules/blogging/src/Volo.Blogging.HttpApi.Client","modules/blogging/src/Volo.Blogging.HttpApi","modules/blogging/src/Volo.Blogging.MongoDB","modules/blogging/src/Volo.Blogging.Web","modules/blogging/src/Volo.Blogging.Admin.Application","modules/blogging/src/Volo.Blogging.Admin.Application.Contracts","modules/blogging/src/Volo.Blogging.Admin.HttpApi","modules/blogging/src/Volo.Blogging.Admin.HttpApi.Client","modules/blogging/src/Volo.Blogging.Admin.Web",# modules/client-simulation"modules/client-simulation/src/Volo.ClientSimulation","modules/client-simulation/src/Volo.ClientSimulation.Web",# modules/docs"modules/docs/src/Volo.Docs.Admin.Application.Contracts","modules/docs/src/Volo.Docs.Admin.Application","modules/docs/src/Volo.Docs.Admin.HttpApi.Client","modules/docs/src/Volo.Docs.Admin.HttpApi","modules/docs/src/Volo.Docs.Admin.Web","modules/docs/src/Volo.Docs.Application.Contracts","modules/docs/src/Volo.Docs.Application","modules/docs/src/Volo.Docs.Domain","modules/docs/src/Volo.Docs.Domain.Shared","modules/docs/src/Volo.Docs.EntityFrameworkCore","modules/docs/src/Volo.Docs.HttpApi.Client","modules/docs/src/Volo.Docs.HttpApi","modules/docs/src/Volo.Docs.MongoDB","modules/docs/src/Volo.Docs.Web",# modules/feature-management"modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts","modules/feature-management/src/Volo.Abp.FeatureManagement.Application","modules/feature-management/src/Volo.Abp.FeatureManagement.Domain","modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared","modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore","modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client","modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi","modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB","modules/feature-management/src/Volo.Abp.FeatureManagement.Web",# modules/identity"modules/identity/src/Volo.Abp.Identity.Application.Contracts","modules/identity/src/Volo.Abp.Identity.Application","modules/identity/src/Volo.Abp.Identity.AspNetCore","modules/identity/src/Volo.Abp.Identity.Domain","modules/identity/src/Volo.Abp.Identity.Domain.Shared","modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore","modules/identity/src/Volo.Abp.Identity.HttpApi.Client","modules/identity/src/Volo.Abp.Identity.HttpApi","modules/identity/src/Volo.Abp.Identity.MongoDB","modules/identity/src/Volo.Abp.Identity.Web","modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity",# modules/identityserver"modules/identityserver/src/Volo.Abp.IdentityServer.Domain","modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared","modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore","modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB","modules/identityserver/src/Volo.Abp.PermissionManagement.Domain.IdentityServer",# modules/permission-management"modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts","modules/permission-management/src/Volo.Abp.PermissionManagement.Application","modules/permission-management/src/Volo.Abp.PermissionManagement.Domain","modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared","modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore","modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client","modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi","modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB","modules/permission-management/src/Volo.Abp.PermissionManagement.Web",# modules/setting-management"modules/setting-management/src/Volo.Abp.SettingManagement.Domain","modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared","modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore","modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB","modules/setting-management/src/Volo.Abp.SettingManagement.Web",# modules/tenant-management"modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts","modules/tenant-management/src/Volo.Abp.TenantManagement.Application","modules/tenant-management/src/Volo.Abp.TenantManagement.Domain","modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared","modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore","modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi.Client","modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi","modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB","modules/tenant-management/src/Volo.Abp.TenantManagement.Web",# modules/users"modules/users/src/Volo.Abp.Users.Abstractions","modules/users/src/Volo.Abp.Users.Domain","modules/users/src/Volo.Abp.Users.Domain.Shared","modules/users/src/Volo.Abp.Users.EntityFrameworkCore","modules/users/src/Volo.Abp.Users.MongoDB",# modules/virtual-file-explorer"modules/virtual-file-explorer/src/Volo.Abp.VirtualFileExplorer.Web",# modules/blob-storing-database"modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain","modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared","modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore","modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB"
)

由于包是一个个项目发布,所以必须定义项目路径。参考以上代码,定义好自己的解决方案和项目路径,就可以进行打包和发布了。

要将包发布到前面搭建的BaGet中,需要修改push_packages.ps1文件,以下是文件的代码:

. ".\common.ps1"$apiKey = $args[0]# Get the version
[xml]$commonPropsXml = Get-Content (Join-Path $rootFolder "common.props")
$version = $commonPropsXml.Project.PropertyGroup.Version# Publish all packages
foreach($project in $projects) {$projectName = $project.Substring($project.LastIndexOf("/") + 1)& dotnet nuget push ($projectName + "." + $version + ".nupkg") -s https://api.nuget.org/v3/index.json --api-key "$apiKey"
}# Go back to the pack folder
Set-Location $packFolder

需要修改的地方是 dotnet nuget push中的url地址,将https://api.nuget.org/v3/index.json修改为http://localhost:1234/v3/index.json就可以了。如果图方便,可以将前面BaGet中定义的ApiKey替换掉"$apiKey",这样就不需要每次执行脚本都输入apiKey了,不过,不建议这样做。

统一包的版本号和包信息

要将包发布到Nuget或BaGet,需要定义包的版本号和包信息,如果一个个项目去定义就很费事了,同样,Abp框架为我们提供了模板,打开Abp框架根目录中的common.props文件,会看到以下代码:

<Project><PropertyGroup> <LangVersion>latest</LangVersion> <Version>3.1.0</Version>   <NoWarn>$(NoWarn);CS1591</NoWarn><PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl><PackageProjectUrl>https://abp.io</PackageProjectUrl><PackageLicenseUrl>https://github.com/abpframework/abp/blob/master/LICENSE</PackageLicenseUrl><RepositoryType>git</RepositoryType><RepositoryUrl>https://github.com/abpframework/abp/</RepositoryUrl></PropertyGroup><ItemGroup><PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" PrivateAssets="All" /></ItemGroup>
</Project>

以上代码中,PropertyGroup中定义的是包的信息,而ItemGroup中定义的是项目要引用的包。只要在项目中引用这个文件,就相当于为项目定义了包信息和引用包。

要在项目中引用这个文件,只需要在创建项目后,打开项目的定义文件,在文件添加以下代码就行了:

<Import Project="..\..\..\common.props" />

以上代码中要注意的是引用的路径,需要根据自己整个项目的文件夹结构来增删..\
如果还是不太清楚整个配置,可以多打开几个Abp框架的项目文件(xxx.csproj)来研究。

包发布

Windows Terminal打开一个powershell窗口,进入build文件夹,先执行build-all-release.ps1生成项目的DLL文件,然后切换到nupkg文件夹,执行pack.ps1进行打包并将包文件自动复制到nupkg文件夹,最后执行push_packages.ps1将包发布到BaGet。如果没写死ApiKey,记得在执行push_packages.ps1时输入ApiKey作为参数。

替换包的DLL

在包发布之后,我们就可以在主项目中,通过安装包的方式来引用模块了。虽然通过包重写的方式可以更换BaGet上的包,但项目已经缓存了所需的包,在版本号没有改变的情况下,是不会去更新包的,因而,必须更改包的版本号再发布,再修改项目引用的包的版本号去更新缓存的包,才会更新包,而这个,对于调试就相当的麻烦了。而比较便捷的方式就是更新缓存的包,这样,项目重新生成的一次,就可使用最新的DLL了。这里的关键,就是怎么更新缓存的包。

Windows Terminal打开一个命令提示符窗口,然后输入以下命令:

dotnet nuget locals all --list

以上命令会列出nuget的缓存包位置:

info : http-cache: /home/user1/.local/share/NuGet/v3-cache
info : global-packages: /home/user1/.nuget/packages/
info : temp: /tmp/NuGetScratch
info : plugins-cache: /home/user1/.local/share/NuGet/plugins-cache

我们需要关注的是全局包(global-packages)的位置。根据输出,打开全局包的位置,会看到包的存放格式都是项目名称\版本号\lib\.NET 框架名称\,只要替换目录中DLL和PDB文件就可以实现缓存更新了。

要实现这个,只需要在执行build-all-release.ps1生成DLL文件后,将DLL复制到缓存目录就行了。当然,这不可能手动一个个去复制,哪就太麻烦了,比发布包还麻烦,我们需要使用脚本来实现自动复制。

同样,我们需要定义一个copy-common.ps1来定义需要复制的项目:

# Paths
$packFolder = (Get-Item -Path "./" -Verbose).FullName
$rootFolder = Join-Path $packFolder "../src/"# List of projects
$projects = (# modules/a这里可以参考/nupkg/common.ps1中的定义)

接下来就是根据$projects中的项目定义来复制DLL了(copy.ps1):

. ".\copy-common.ps1"$destiontionRoot = $args[0]
# Create all packages
foreach($project in $projects) {$projectFolder = Join-Path $rootFolder $project $projectFolder = Join-Path $projectFolder "bin/Release" $framework = "netstandard2.0"$dllFolder = Join-Path $projectFolder $frameworkif(!(Test-Path $dllFolder)){$framework = "netcoreapp3.1"$dllFolder = Join-Path $projectFolder $framework} $projectName = $project.Substring($project.LastIndexOf("/") + 1)$dllFile = Join-Path $dllFolder ($projectName + ".dll")$pdbFile = Join-Path $dllFolder ($projectName + ".pdb")$destination = Join-Path $destiontionRoot ($projectName + "/0.0.1/lib/" + $framework)Write-Host("Copy file:" + $dllFile)Copy-Item -Path $dllFile  -Destination $destination Copy-Item -Path $pdbFile  -Destination $destination }# Go back to the pack folder
Set-Location $packFolder

代码会遍历$projects定义中的项目,然后组合出项目DLL文件所在的位置。这里需要注意的是使用框架的版本号,如果使用的是netstandard2.1,则需要将$framework的值修改为netstandard2.1,同理,netcoreapp3.1也需要根据框架版本号做相应的修改。项目DLL文件所在位置确定后,就可使用Copy-Item将DLL复制到缓存目录了。这里要注意的是缓存目录里项目的版本号,也就是变量$destination中的0.0.1需要修改为对应的版本号。

笔者将copy-common.ps1copy.ps1都放到了build文件夹,这样在执行了build-all-release.ps1后,就不需要切换文件夹,直接执行copy.ps1进行复制,非常的方便。

如果项目有新增模块,需要修改脚本,将模块发布一次,再在项目引用模块,以便在全局缓存中缓存模块,才可进行替换。

Abp.Io(vNext)开发体会相关推荐

  1. Abp.io(vNext)开发日志:单页面应用与外部/社交登录

    @TOC Abp.io(vNext)开发日志:单页面应用与外部/社交登录 如果不使用外部/社交登录,实现很简单,使用Identity Server 4的令牌端点(Toekn EndPoint)实现密码 ...

  2. abp.io(vNext)部署备忘

    编译镜像 编译使用的Dockerfile文件是vs自动创建的,存在以下几个问题: 编译使用的aspnet包是3.1-buster-slim,sdk包是3.1-buster,编译后在centOS 8上跑 ...

  3. 索尼游戏手柄SP2的开发体会

    索尼游戏手柄SP2的开发体会 1.PS手柄介绍 接收器引脚输出: 通信时序: 2.代码解读 3.库文件解读 ps2手柄是索尼的PlayStation2游戏机的遥控手柄. 该款手柄的通讯协议被游戏爱好者 ...

  4. 如何使用ABP进行软件开发之基础概览

    ABP框架简述 1)简介 在.NET众多的技术框架中,ABP框架(本系列中指aspnetboilerplate项目)以其独特的魅力吸引了一群优秀开发者广泛的使用. 在该框架的赋能之下,开发者可根据需求 ...

  5. 微信小程序云开发体会——总结软件工程导论大作业

    微信小程序云开发体会--总结软件工程导论大作业 前言 第一次接触 具体难题 好用的技术 开发完之后的体会 无法不热爱更多 前言 可能大家完成这次作业都会选择比较擅长的领域--网页前后端.这的确是比较稳 ...

  6. 工作流系统之二十五 .net工作流系统开发体会

    .net工作流系统开发体会 公司的eworkflow自定义工作流系统,最初是开发了java版的.待java版的功能稳定后,就开始开发.net版的. java版的eworkflow工作流系统,我们没有依 ...

  7. 绝对精品推荐做前端的看下:Web前端开发体会十日谈

    20151208感悟: 前端人的角度来看的话,感觉像是阅读一个大牛前端的全部武功的一个秘籍说明,里面的思想高价值蛋白真是太多太多,推荐看. Web前端开发体会十日谈 一直想写这篇"十日谈&q ...

  8. 一、快速搭建ABP Vnext开发环境

    关于Abp Vnext框架基础知识,官方文档已有很详细的阐述.此系列文章皆以实例为主,关键地方会包含博主个人的见解,所有的文章皆为原创,并且附带源码. 顺便说一下,我的所有示例均使用angular作为 ...

  9. 《ABP Framework 极速开发》 - 教程首发

    ‍ 写在发布之前 强烈建议每一位小伙伴都应该好好看看 ABP Framework 官方文档,可能有很多的小伙伴跟我刚开始的感觉一样"一看文档深似海",看完文档之后,想要上手却找不着 ...

最新文章

  1. github下载源码也用命令进行安装包的联系
  2. scanf 接收 空格 输入_【C语言】- printf 和scanf 函数详解!
  3. python 列表转图结构_Python读取网络(图)边列表数据进而转化为邻接矩阵
  4. VMware Workstation 与 Server 的区别
  5. mongodb 导出一条数据_将 MongoDB 导出成 csv
  6. Spring帖子汇总
  7. 自然语言18.2_NLTK命名实体识别
  8. DPDK分析——UIO
  9. atitit 面试问题表 侧重于项目和业务描述方面.v2 良好的标准:: 1.回答问题比较流畅,较少出现停顿现象,较少犹豫 2.回答有条理清晰 不杂乱 3.回答较为丰富内容 4.精神状态紧张
  10. 对外汉语语料库有哪些_史上最全最新的语料库资源大全【对外汉语教学研究工具】...
  11. 十天学会单片机(3)发光管闪烁,蜂鸣器发声
  12. 2017年全国大学生电子设计竞赛报告(F题)调幅信号处理实验电路
  13. 八爪鱼导出到mysql数据库_怎么将八爪鱼采集器数据导出数据库
  14. 手机计算机桌面图标恢复,三种方法快速找回桌面图标(附电脑文件恢复教程)...
  15. 百格活动告诉你为什么你始终做不好活动营销?
  16. 打造中国版ChatGPT,国内有哪些学术力量能抢滩?
  17. 2.18 设置language和中文输入法
  18. Python魔法方法指南
  19. 工业机器人pallet指令_爱普生机器人编程手册
  20. 从一代名将到一代名流 法切蒂的蓝黑人生

热门文章

  1. Jetsons刷机流程
  2. 中证1000期指上市带来的交易机会
  3. python内置函数open_Python内置函数(47)——open
  4. 微信小程序-订单页面
  5. 微信使用技巧及微信营销软件
  6. indesign可以换暂存盘吗_InDesign CS5_快捷键大全
  7. dell服务器r730老自动重启_戴尔R730 R720服务器故障维修
  8. Thinkpad T470p 加固态硬盘小记
  9. PHP超简易页面数据写入excel
  10. STM32CubeMX配置SD卡+DMA+Fatfs文件系统