{"record":{"id":"1bf1dbddeabf6ebd","repo":"JeffreySu/WeiXinMPSDK","slug":"nameof-out-order-no-query-id","errorCode":null,"errorMessage":"{nameof(out_order_no)}与{query_id}必填其中一个.不允许都填写或都不填写","messagePattern":"(.+?)与(.+?)必填其中一个\\.不允许都填写或都不填写","errorType":"validation","errorClass":"TenpayApiRequestException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/PayScore/PayScoreApis.cs","lineNumber":211,"sourceCode":"            return await tenPayApiRequest.RequestAsync<CreateServiceOrderReturnJson>(url, data, timeOut);\n        }\n\n        /// <summary>\n        /// 查询支付分订单接口\n        /// <para>用于查询单笔微信支付分订单详细信息。</para>\n        /// <para><see href=\"https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_15.shtml\">更多详细请参考微信支付官方文档</see></para>\n        /// </summary>\n        /// <param name=\"out_order_no\">商户系统内部服务订单号（不是交易单号），与创建订单时一致，商户单号与回跳查询id必填其中一个.不允许都填写或都不填写。</param>\n        /// <param name=\"query_id\">微信侧回跳到商户前端时用于查单的单据查询id。详见章节“小程序跳转接口，回跳商户接口”，商户单号与回跳查询id必填其中一个.不允许都填写或都不填写。</param>\n        /// <param name=\"service_id\">服务ID,该服务ID有本接口对应产品的权限</param>\n        /// <param name=\"appid\"> 微信公众平台分配的与传入的商户号建立了支付绑定关系的appid，可在公众平台查看绑定关系，此参数需在本系统先进行配置。</param>\n        /// <param name=\"timeOut\">超时时间，单位为ms</param>\n        /// <returns></returns>\n        public async Task<QueryServiceOrderReturnJson> QueryServiceOrderAsync(string out_order_no, string query_id, string service_id, string appid, int timeOut = Config.TIME_OUT)\n        {\n            if ((out_order_no is null && query_id is null) || (out_order_no is not null && query_id is not null))\n            {\n                throw new TenpayApiRequestException($\"{nameof(out_order_no)}与{query_id}必填其中一个.不允许都填写或都不填写\");\n            }\n\n            var url = ReurnPayApiUrl($\"{Senparc.Weixin.Config.TenPayV3Host}/{{0}}v3/payscore/serviceorder?service_id={service_id}&appid={appid}\");\n\n\n            url += out_order_no is not null ? $\"&out_order_no={out_order_no}\" : \"\";\n            url += query_id is not null ? $\"&query_id={query_id}\" : \"\";\n\n            TenPayApiRequest tenPayApiRequest = new(_tenpayV3Setting);\n            return await tenPayApiRequest.RequestAsync<QueryServiceOrderReturnJson>(url, null, timeOut, ApiRequestMethod.GET);\n        }\n\n        /// <summary>\n        /// 取消支付分订单接口\n        /// <para>微信支付分订单创建之后，由于某些原因导致订单不能正常支付时，可使用此接口取消订单。</para>\n        /// <para>订单为以下状态时可以取消订单：CREATED（已创单）、DOING（进行中）（包括商户完结支付分订单后，且支付分订单收款状态为待支付USER_PAYING）。</para>\n        /// <para>更多详细请参考 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_16.shtml </para>\n        /// </summary>","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/PayScore/PayScoreApis.cs#L193-L229","documentation":"QueryServiceOrderAsync (PayScoreApis.cs:211) queries a WeChat Pay Score (支付分) service order, which must be identified by exactly one of out_order_no (merchant order number) or query_id. The library throws TenpayApiRequestException when both are null or both are provided, because WeChat requires exactly one query key.","triggerScenarios":"Calling QueryServiceOrderAsync with both out_order_no and query_id null, or with both non-null; e.g. passing empty strings/logic that failed to choose one identifier.","commonSituations":"Copy-pasted call sites that always pass both arguments; business code that has both identifiers cached and forwards both; after a refactor where the query id became optional but the out_order_no path wasn't chosen exclusively.","solutions":["Pass exactly one identifier: either out_order_no or query_id, leaving the other null","Choose out_order_no when querying by your own order number, query_id when the id came from a WeChat callback/notification","Wrap the call in a helper that asserts exactly one of the two values is present"],"exampleFix":"// before (both set — throws)\nawait api.QueryServiceOrderAsync(outOrderNo, queryId, serviceId, appid);\n\n// after\nawait api.QueryServiceOrderAsync(outOrderNo, null, serviceId, appid);","handlingStrategy":"validation","validationCode":"if ((outOrderNo == null) == (queryId == null))\n    throw new InvalidOperationException(\"Exactly one of out_order_no / query_id must be provided\");","typeGuard":null,"tryCatchPattern":"try { await api.QueryServiceOrderAsync(outOrderNo, queryId, serviceId, appid); }\ncatch (TenpayApiRequestException ex) when (ex.Message.Contains(\"out_order_no\"))\n{ logger.LogError(ex, \"Must pass exactly one of out_order_no/query_id\"); throw; }","preventionTips":["Build a wrapper API taking a discriminated parameter (either order number or query id)","Never pass both identifiers, even when both are known","Add argument checks in your service layer before calling the SDK"],"tags":["tenpay","payscore","validation","parameters"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"be573f6f94bdbf718dd5f6cdecb137fbc7ff651e","analyzedAt":"2026-09-12T10:01:50.733Z","contentChangedAt":"2026-09-12T10:01:50.733Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}