21 KiB
KJD WebService 迁移文档(.NET Framework 4.6.2 → .NET 10)
生成日期:2026-08-14 适用范围:旧项目
D:\Works\KJD Cef138\KJDService→ 新项目D:\Works\StoreHub\StoreHub.KJDWebService
1. 迁移背景与目标
| 项目 | 说明 |
|---|---|
| 旧项目 | D:\Works\KJD Cef138\KJDService,ASP.NET WebService(*.asmx),.NET Framework 4.6.2,MySQL(MySql.Data) |
| 新项目 | D:\Works\StoreHub\StoreHub.KJDWebService,.NET 10 + ASP.NET Core,宿主为 D:\Works\StoreHub\StoreHub(Web 项目,已引用 KJDWebService) |
| 迁移目标 | 功能等价迁移到 .NET 10;不优化代码;模型照抄;Manage 方法内逻辑不修改;执行语句改为参数方式;对外路由保持一致 |
新项目仓库结构(解决方案 D:\Works\StoreHub\StoreHub.slnx):
D:\Works\StoreHub\
├─ StoreHub\ # Web 宿主(Program.cs,引用 KJDWebService)
├─ StoreHub.Framework\ # 公共框架(IOC、FreeSql、ApiResult、SqlRepository)
├─ StoreHub.KJDWebService\ # 本次迁移目标项目(业务代码)
├─ StoreHub.Services\ # 其他服务
└─ Core\
2. 新项目目录结构规范(必须严格遵循)
StoreHub.KJDWebService/
├─ Commons/ # 公共工具(旧 Utils 照搬)
├─ Controllers/ # API(旧 *.asmx 的每个 WebMethod → Action)
├─ Dtos/ # DTO 目录
├─ Models/ # 模型目录(旧 Model 照抄)
├─ Services/ # 服务目录(旧 BLL/*Manage → *Service)
├─ Repositorys/ # SqlRepository(框架提供)
└─ Startup.cs # IStartup 入口
3. 核心编码规范
3.1 Service 规范(强制)
- 所有 Service 都要注入
SqlRepository sqlRepository; - 用
_sqlRepository.Ado.ExecuteDataTable(...)执行 SQL 语句; - Service 需实现
ITransientDependency/IScopedDependency标记接口,由框架自动注册,方便 Controller 构造注入调用。
参考 Services/DemoService.cs(已存在的示例):
using MAX.Core.DependencyInjection;
using StoreHub.Framework.Repositorys;
namespace StoreHub.KJDWebService.Services
{
public class DemoService : ITransientDependency
{
private readonly SqlRepository _sqlRepository;
public DemoService(SqlRepository sqlRepository)
{
_sqlRepository = sqlRepository;
}
public bool Test()
{
_sqlRepository.Ado.ExecuteDataTable("select * from user");
return true;
}
public bool Test2()
{
return true;
}
}
}
SqlRepository(StoreHub.Framework/Repositorys/SqlRepository.cs):
public class SqlRepository : IScopedDependency
{
public IAdo Ado { get; }
public SqlRepository([FromKeyedServices("KJDDB")] IFreeSql fsql)
{
Ado = fsql.Ado;
}
}
3.2 服务注册机制
框架(StoreHub.Framework/DependencyInjection/ServiceCollectionExtensions.cs)自动扫描并注册所有实现以下标记接口的类型:
| 标记接口 | 生命周期 |
|---|---|
ISingletonDependency |
Singleton |
IScopedDependency |
Scoped |
ITransientDependency |
Transient |
因此:Manage 对应的 Service 只需实现上述任一标记接口即可被自动注册,无需手写 DI 代码。Controller 构造函数直接注入 Service 即可。
3.3 Controller 规范
参考现有 Controllers/Login.cs:
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]/[action]")]
public class Login : ControllerBase
{
private readonly DemoService _userService;
public Login(DemoService userService)
{
_userService = userService;
}
[HttpGet]
public ApiResult<bool> Loinout()
{
_userService.Login();
return ApiResult.Success(true);
}
}
⚠️ 迁移注意:旧接口路由是
/{前缀}/{方法名}(如/user/user_login),为保持路由一致,每个业务 Controller 应使用旧前缀路由(见第 5.3 节),而不是统一api/v1/[controller]/[action]。是否保留api/v{version}前缀需与调用方确认。
4. 旧项目 → 新项目映射规则
| 旧项目 | 新项目 | 说明 |
|---|---|---|
*.asmx / *.asmx.cs(20 个) |
Controllers/*Controller.cs |
asmx 的每个 [WebMethod] → Controller 的一个 Action |
BLL/*/*Manage.cs(23 个) |
Services/*Service.cs |
Manage 类 → Service 类,注入 SqlRepository |
Global.asax.cs 中的 URL 重写规则 |
Controller 的 Route 特性 | 路由保持与旧地址一致 |
Model/*.cs(47 个) |
Models/ |
照抄,不做任何改动 |
Utils/*.cs(含 Extension、Helper) |
Commons/ |
照搬(公共工具) |
Web.config 连接串/业务配置 |
appsettings.json |
ConnKJD → KJDConnection(keyed KJDDB)等 |
MysqlUtils(MySql.Data) |
_sqlRepository.Ado(FreeSql IAdo) |
SQL 执行方式改为参数化(见第 7 节) |
NaiBa.Util.*(Extension/Helper 命名空间) |
迁移后统一到新命名空间 | 注意 using 同步调整 |
5. 详细迁移清单
5.1 asmx 服务 → Controller 映射(共 20 个服务 / 356 个 WebMethod)
| # | asmx 服务(旧) | WebMethod 数 | 依赖的 Manage | 建议 Controller(新) |
|---|---|---|---|---|
| 1 | UserService.asmx | 18 | UserManage、UpdateManage(代码中为 UpadteManage,见风险 9.2) |
UserController |
| 2 | ShopService.asmx | 18 | ShopManage | ShopController |
| 3 | OrderService.asmx | 8 | OrderManage | OrderController |
| 4 | ProductService.asmx | 24 | ProductManage | ProductController |
| 5 | ProductThirdService.asmx | 18 | ProductThirdManage | ProductThirdController |
| 6 | PriceService.asmx | 8 | PriceManage | PriceController |
| 7 | UpdateService.asmx | 4 | UpdateManage | UpdateController |
| 8 | ToolService.asmx | 2 | ToolManage | ToolController |
| 9 | BXXUserService.asmx | 18 | BXXUserManage | BXXUserController |
| 10 | BXXShopService.asmx | 24 | BXXShopManage、WXShopManage | BXXShopController |
| 11 | BXXProductService.asmx | 44 | BXXProductManage、WXShopManage | BXXProductController |
| 12 | BXXProductThirdService.asmx | 14 | BXXProductThirdManage | BXXProductThirdController |
| 13 | BXXPriceService.asmx | 12 | BXXPriceManage | BXXPriceController |
| 14 | DYUserService.asmx | 11 | DYUserManage | DYUserController |
| 15 | DYShopService.asmx | 13 | DYShopManage | DYShopController |
| 16 | WXUserService.asmx | 22 | WXUserManage、WXOemManage | WXUserController |
| 17 | WXShopService.asmx | 38 | WXShopManage、WXExpressOptimizeManage | WXShopController |
| 18 | WXProductService.asmx | 34 | WXProductManage、BXXProductManage | WXProductController |
| 19 | WXOrderService.asmx | 25 | WXOrderManage | WXOrderController |
| 20 | WXShopRevenueStatistics.asmx | 1 | WXShopRevenueStatisticsManage | WXShopRevenueStatisticsController |
Global.asax.cs中还引用了DYProductService、DYProductThirdService、DYPriceService、WXProductThirdService、WXPriceService的重写目标,但旧项目中不存在这些 asmx 文件(见 9.1)。
5.2 Manage → Service 映射(23 个)
| BLL 目录 | Manage(旧) | Service(新) |
|---|---|---|
| BLL/KJD | UserManage.cs | UserService.cs |
| BLL/KJD | ShopManage.cs | ShopService.cs |
| BLL/KJD | OrderManage.cs | OrderService.cs |
| BLL/KJD | ProductManage.cs | ProductService.cs |
| BLL/KJD | ProductThirdManage.cs | ProductThirdService.cs |
| BLL/KJD | PriceManage.cs | PriceService.cs |
| BLL/KJD | UpdateManage.cs | UpdateService.cs |
| BLL/KJD | ToolManage.cs | ToolService.cs |
| BLL/BXX | BXXUserManage.cs | BXXUserService.cs |
| BLL/BXX | BXXShopManage.cs | BXXShopService.cs |
| BLL/BXX | BXXProductManage.cs | BXXProductService.cs |
| BLL/BXX | BXXProductThirdManage.cs | BXXProductThirdService.cs |
| BLL/BXX | BXXPriceManage.cs | BXXPriceService.cs |
| BLL/DYXD | DYUserManage.cs | DYUserService.cs |
| BLL/DYXD | DYShopManage.cs | DYShopService.cs |
| BLL/WXXD | WXUserManage.cs | WXUserService.cs |
| BLL/WXXD | WXShopManage.cs | WXShopService.cs |
| BLL/WXXD | WXProductManage.cs | WXProductService.cs |
| BLL/WXXD | WXOrderManage.cs | WXOrderService.cs |
| BLL/WXXD | WXShopRevenueStatisticsManage.cs | WXShopRevenueStatisticsService.cs |
| BLL/WXXD | WXOemManage.cs | WXOemService.cs |
| BLL/WXXD | WXExpressOptimizeManage.cs | WXExpressOptimizeService.cs |
| (备注) | ProductThridManage、UpadteManage |
旧代码中仅注释/疑似笔误,见 9.2 |
5.3 Global.asax 路由映射表(路由必须保持一致)
Global.asax.cs 的 Application_BeginRequest 中,把不带 .asmx 的友好 URL 重写到对应的 asmx。迁移后需在 Controller 上配置等价路由:
| 旧 URL 前缀 | 重写到(旧) | 建议新路由(保持一致) |
|---|---|---|
/user/{method} |
UserService.asmx/{method} | [Route("user/[action]")] UserController |
/shop/{method} |
ShopService.asmx/{method} | [Route("shop/[action]")] ShopController |
/order/{method} |
OrderService.asmx/{method} | [Route("order/[action]")] OrderController |
/product/{method} |
ProductService.asmx/{method} | [Route("product/[action]")] ProductController |
/product_third/{method} |
ProductThirdService.asmx/{method} | [Route("product_third/[action]")] ProductThirdController |
/price/{method} |
PriceService.asmx/{method} | [Route("price/[action]")] PriceController |
/update/{method} |
UpdateService.asmx/{method} | [Route("update/[action]")] UpdateController |
/bxx_user/{method} |
BXXUserService.asmx/{method} | [Route("bxx_user/[action]")] BXXUserController |
/bxx_shop/{method} |
BXXShopService.asmx/{method} | [Route("bxx_shop/[action]")] BXXShopController |
/bxx_product/{method} |
BXXProductService.asmx/{method} | [Route("bxx_product/[action]")] BXXProductController |
/bxx_product_third/{method} |
BXXProductThirdService.asmx/{method} | [Route("bxx_product_third/[action]")] BXXProductThirdController |
/bxx_price/{method} |
BXXPriceService.asmx/{method} | [Route("bxx_price/[action]")] BXXPriceController |
/dyxd_user/{method} |
DYUserService.asmx/{method} | [Route("dyxd_user/[action]")] DYUserController |
/dyxd_shop/{method} |
DYShopService.asmx/{method} | [Route("dyxd_shop/[action]")] DYShopController |
/dyxd_product/{method} |
DYProductService.asmx(旧项目不存在) | 待确认 |
/dyxd_product_third/{method} |
DYProductThirdService.asmx(旧项目不存在) | 待确认 |
/dyxd_price/{method} |
DYPriceService.asmx(旧项目不存在) | 待确认 |
/wxxd_user/{method} |
WXUserService.asmx/{method} | [Route("wxxd_user/[action]")] WXUserController |
/wxxd_shop/{method} |
WXShopService.asmx/{method} | [Route("wxxd_shop/[action]")] WXShopController |
/wxxd_product/{method} |
WXProductService.asmx/{method} | [Route("wxxd_product/[action]")] WXProductController |
/wxxd_product_third/{method} |
WXProductThirdService.asmx(旧项目不存在) | 待确认 |
/wxxd_price/{method} |
WXPriceService.asmx(旧项目不存在) | 待确认 |
/wxxd_order/{method} |
WXOrderService.asmx/{method} | [Route("wxxd_order/[action]")] WXOrderController |
/wxxd_shop_revenue_statistics/{method} |
WXShopRevenueStatistics.asmx/{method} | [Route("wxxd_shop_revenue_statistics/[action]")] WXShopRevenueStatisticsController |
/ToolService.asmx/{method}(无前缀) |
直接访问 | [Route("ToolService/[action]")] ToolController |
说明:旧 URL 没有
api/v1前缀。若新项目仍使用api/v{version}/[controller]/[action]全局模板,则旧调用方 URL 会变化,属于不保持路由一致。默认方案:给各 Controller 单独设置与旧前缀一致的路由。
5.4 Model 清单(47 个,照抄)
Model/ 根目录(14 个):CommentParam、DBPriceResultParam、DBProdDbIdMapProductIdResultParam、DBProductResultParam、JSTDownProdSkuInfo、OrderParam、ProductPurchasePriceResultParam、ProductSelectResultParam、Result、SkuImgResult、TemuDBOrderInfo、UserLoginResultParam、WXAddressInfo、WxProdSecretSpuIdShopIdMapParam、WXShopDefaultAddressInfo
Model/ErpModel/(1 个):ErpMerchantInfo
Model/PddModel/(7 个):BuyerLoginInfo、PDDMaterialInfo、PDDProductDecorationInfo、PDDProductDetailInfo、PDDProductInfo、PDDProductPropertyInfo、PDDSizeSpecInfo
Model/ShopModel/(4 个):JitCardCodeParam、JSTListProductSkuInfo、ShopParam、sku_img_replace
Model/WxModel/(20 个):oem、oms_wei_external_procurement_after_sale_info、oms_wei_external_procurement_log、oms_wei_order、oms_wei_order_item、oms_wei_refund、order_item_ext、order_pdd_buyer_after_sale、order_pdd_buyer_order、user_payment_record_info、user_points_record_info、WXBuyUrlNotesInfo、WXClientProductInfoLite、WXGetEditProductInfoLite、WxOptimizeExpressInfo、WXOrderAmountInfo、WXOrderDecryptAddressInfo、wx_qualification_image_info
规则:所有 model 照抄,字段、属性、类名、命名空间规则均不修改(仅按需调整命名空间以适配新项目编译)。
5.5 Utils → Commons 清单(照搬)
| 旧 Utils 文件 | 新位置 | 说明 |
|---|---|---|
| EncrypUtil.cs | Commons/ | 加密工具 |
| HtmlUtils.cs | Commons/ | HTML/URL 工具 |
| HttpUtils.cs | Commons/ | HTTP 工具 |
| JsonUtils.cs | Commons/ | JSON 工具 |
| RandomUtils.cs | Commons/ | 随机数工具 |
| RegexUtils.cs | Commons/ | 正则解析(Manage 大量依赖) |
| TimeUtils.cs | Commons/ | 时间工具 |
| Extension/(Convert、Enum、Exception、Linq、Validate) | Commons/Extension/ | 扩展方法(Manage 依赖 NaiBa.Util.Extension) |
| Helper/(HtmlHelper、JsonHelper、ReflectionHelper、RegexHelper) | Commons/Helper/ | 辅助类 |
| ApiRequestLogger.cs | (保留在旧项目或移入新项目) | 请求录制,用于迁移后回放校验 |
6. 迁移实施步骤
- 确认新项目骨架:
D:\Works\StoreHub\StoreHub.KJDWebService已存在,Commons、Controllers、Dtos、Models、Services目录已建,DemoService、SqlRepository、Startup.cs、Login.cs示例已就位。 - Models 迁移:把旧
Model/下 47 个文件照抄到新项目Models/(保留子目录结构或平铺均可,类定义一字不改)。 - Commons 迁移:把旧
Utils/(含 Extension、Helper)照搬进Commons/,调整命名空间与using以适配 .NET 10 编译。 - Services 迁移:按 5.2 表,把每个
*Manage.cs转换为*Service.cs:- 类实现
ITransientDependency; - 构造函数注入
SqlRepository _sqlRepository; - 方法逻辑原样保留(不做优化、不改算法);
- 把
new MysqlUtils(conn)+mySql.XXX(sql)的调用改为_sqlRepository.Ado.XXX(sql, 参数)(见第 7 节)。
- 类实现
- Controllers 迁移:按 5.1 表,把每个
*.asmx.cs的[WebMethod]转为 Controller Action,并保留:- 请求体读取逻辑(等价于旧
GetRequestJsonString():body JSON 为空时回退 QueryString); - 响应格式(旧接口
Context.Response.Write(result)输出原始 JSON 字符串{code,msg,...},新接口建议return Content(result, "text/html;charset=utf-8")保持调用方兼容)。
- 请求体读取逻辑(等价于旧
- 路由配置:按 5.3 表给 Controller 配置与旧前缀一致的路由。
- 配置迁移:把旧
Web.config的连接串与业务配置迁到宿主appsettings.json(见第 8 节)。 - 编译与验证:编译通过后,用旧项目
App_Data/ApiLogs/下录制的请求做回放校验(ApiRequestLogger录制了请求与响应),逐接口比对返回结果。
7. SQL 执行方式改造规范(改为参数方式)
旧代码示例(字符串拼接 + 手工转义):
string conn = System.Configuration.ConfigurationManager.ConnectionStrings["ConnKJD"].ConnectionString;
MysqlUtils mySql = new MysqlUtils(conn);
string sql = "select * from user where name = '" + name.Replace("'", "\\'") + "'";
var dt = mySql.ExecuteDataTable(sql);
mySql.Close();
新代码示例(参数化,逻辑不变):
string sql = "select * from user where name = @name";
var dt = _sqlRepository.Ado.ExecuteDataTable(sql, new { name = name });
MysqlUtils 方法 → FreeSql IAdo 对照:
| 旧(MysqlUtils) | 新(_sqlRepository.Ado) |
|---|---|
| ExecuteDataTable(sql) | ExecuteDataTable(sql, 参数) |
| ExecuteDataTableRow(sql) | ExecuteDataTable(sql, 参数) 取第一行 |
| ExecuteRowCount(sql) | ExecuteDataTable(sql, 参数).Rows.Count 或 ExecuteScalar |
| ExecuteFirst / ExecuteFirstInt / ExecuteFirstDecimal | ExecuteScalar / ExecuteDataTable |
| ExecuteAffectedRows / ExecuteNonQuery | ExecuteNonQuery |
| ExecuteInsertId | ExecuteInsertId / ExecuteScalar(select last_insert_id()) |
| ExecuteExists | ExecuteDataTable 判断行数 |
| 事务(IsUseTrans / Commit / RollBack) | IAdo 事务 API(BeginTransaction / Commit / Rollback) |
| Close() | 连接池自动管理,无需手动 Close |
规则:只把拼接 SQL 改为参数方式,不改变 SQL 语义与业务逻辑。
8. 配置迁移(Web.config → appsettings.json)
旧 Web.config 关键配置:
| 旧配置(Web.config) | 新配置(appsettings.json) | 说明 |
|---|---|---|
connectionStrings: ConnKJD |
ConnectionStrings: KJDConnection |
框架已用 KJDConnection 注册 keyed IFreeSql("KJDDB")(见 StoreHub.Framework/Startup.cs) |
connectionStrings: ConnKJDBAK |
ConnectionStrings: KJDBAKConnection(建议) |
备份库连接串,业务是否使用需确认 |
connectionStrings: UpdateVersion / UpdateFileDir / UpdateNewUrl / UpdateExe / UpdateExeChk / LowVersion / LimitVersion 等 |
appsettings.json 自定义配置节 |
供 UpdateService 使用 |
connectionStrings: GetReturnPackage / GetWXRecommendHotProd / ... |
同上 | 业务开关类配置 |
connectionStrings: IsKeepBase64UploadImgFile / UpdateWxFindOrderFileDir / UpdateWxFindOrderUrl / WxFindOrderLimitVersion / WxFindOrderLowVersion |
同上 | 业务配置 |
当前
appsettings.json中的KJDConnection是占位值(Server=localhost;...),迁移时必须替换为旧ConnKJD的真实连接串。
9. 风险与待确认项
- Global.asax 中存在指向不存在 asmx 的路由:
/dyxd_product/、/dyxd_product_third/、/dyxd_price/、/wxxd_product_third/、/wxxd_price/重写目标文件(DYProductService、DYProductThirdService、DYPriceService、WXProductThirdService、WXPriceService)在旧项目中不存在。迁移时按原样保留路由定义,但需与业务确认这些前缀是否仍被调用方使用。 UserService.asmx.cs的GetUpdateInfo引用new UpadteManage():旧项目中不存在UpadteManage类(疑似UpdateManage笔误),迁移时需修正为UpdateManage或与业务确认。- 响应格式兼容:旧接口返回的
{code,msg,...}是原始 JSON 字符串,字段名/大小写/结构必须原样保留;不要直接替换成新框架ApiResult<T>的序列化格式,除非调用方同步升级。 - 请求读取方式:旧
GetRequestJsonString()先读 body,body 为空时拼 QueryString;Controller 需保留等价实现。 - 多库支持:旧代码可能动态切换
ConnKJD/ConnKJDBAK;新框架目前只注册了KJDDB与UserDB两个 keyed IFreeSql,若业务用到其他库需在StoreHub.Framework/Startup.cs中补充注册。 - 上传/文件接口:
UpdateService.DownloadFile(返回 byte[])、Upload/目录文件读写等,迁移时注意 IFormFile / 静态文件映射的等价实现。 MachineKey/ 会话:旧配置中有machineKey,若接口依赖加密校验(如EncrypUtil.Encryption的time/code校验),仅为应用内算法,不依赖 ASP.NET 会话,可直接沿用EncrypUtil。- Base64 图片:
IsKeepBase64UploadImgFile等业务开关需迁移,保证行为一致。
10. 验收标准
- 新项目可编译通过(.NET 10);
- 20 个 asmx 服务全部有对应 Controller,356 个 WebMethod 全部有对应 Action;
- 23 个 Manage 全部有对应 Service,且均注入 SqlRepository、使用
_sqlRepository.Ado.ExecuteDataTable; - 所有 Model 照抄未改动;
- Manage 方法内业务逻辑未做任何优化/修改;
- SQL 语句全部参数化,无字符串拼接注入风险;
- 所有 Service 均已注册(实现 ITransientDependency / IScopedDependency),Controller 可正常注入;
- 路由与旧 URL 保持一致(含 Global.asax 全部重写规则);
- 使用
App_Data/ApiLogs/录制的请求做回放,新旧响应一致; - 连接串/业务配置迁移完成(KJDConnection 为真实连接串)。
本文档依据旧项目源码现状与目标项目骨架生成,供迁移实施与验收使用。