使用.NET向IoT Hub上传配置/部署时遇BadRequest错误求助
解决.NET向IoT Hub上传Edge配置时的BadRequest错误
问题场景
需求为使用.NET向Azure IoT Hub上传IoT Edge配置/部署(非直接部署到单设备),调用API时返回BadRequest错误。
主代码
var iotHubName = "[iothubname].azure-devices.net"; var policyName = "iothubowner"; var key = "[iothubownerkey]"; var token = ConstructToken(iotHubName, policyName, key); var result = DeployConfiguration(iotHubName, token); Console.WriteLine($"Press a key to exit {result}");
API请求代码
private static string DeployConfiguration(string iotHubName, string token) { using var client = new HttpClient(); client.DefaultRequestHeaders.Add("Authorization", token); var body = File.ReadAllText("deloyment.manifest.json"); var stringContent = new StringContent(body, Encoding.UTF8, "application/json"); var restUriPut = $"https://{iotHubName}/configurations/configid?api-version=2020-05-31-preview"; using var resultPut = client.PutAsync(restUriPut, stringContent).Result; return resultPut.StatusCode.ToString(); }
原部署清单(deployment.manifest.json)
{ "modulesContent": { "$edgeAgent": { "properties.desired": { "schemaVersion": "1.1", "runtime": { "type": "docker", "settings": {} }, "systemModules": { "edgeAgent": { "env": { "SendRuntimeQualityTelemetry": { "value": false } }, "settings": { "image": "mcr.microsoft.com/azureiotedge-agent:1.4" }, "type": "docker" }, "edgeHub": { "restartPolicy": "always", "settings": { "image": "mcr.microsoft.com/azureiotedge-hub:1.4", "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}" }, "status": "running", "type": "docker" } }, "modules": { "OPCPublisher": { "env": { "ApplicationCertificateSubjectName": { "value": "C=US,L = Redmond,O=Contoso Inc.,OU=Contoso IT Security,CN=opcpublisher,DC=victor" }, "ApplicationName": { "value": "opcpublisher" }, "Test": { "value": "true" } }, "restartPolicy": "always", "settings": { "image": "mcr.microsoft.com/iotedge/opc-publisher:latest", "createOptions": "{\"Hostname\":\"opcpublisher\",\"Cmd\":[\"-c\",\"--PkiRootPath=/mount/pki\",\"--pf=/mount/published_nodes.json\",\"--lf=/mount/publisher.log\",\"--mm=PubSub\",\"--me=Json\",\"--fd=false\",\"--bs=100\",\"--bi=1000\",\"--di=20\",\"--aa\"],\"HostConfig\":{\"Mounts\":[{\"Type\":\"bind\",\"Source\":\"/opcpublisher\",\"Target\":\"/mount\"}]}}" }, "status": "running", "type": "docker" } } } }, "$edgeHub": { "properties.desired": { "schemaVersion": "1.1", "storeAndForwardConfiguration": { "timeToLiveSecs": 7200 }, "routes": { "route": { "route": "FROM /messages/* INTO $upstream" } } } }, "OPCPublisher": { "properties.desired": {} } } }
解决方案
核心问题
BadRequest错误的根源是批量配置部署的API请求体格式和单设备直接部署的格式不一致。单设备部署仅需提交modulesContent,但IoT Hub的批量配置部署需要包含顶层配置字段,将模块内容包裹在content下。
修改步骤
调整部署清单结构
将原modulesContent包裹到content字段中,补充必要的顶层配置项:{ "id": "configid", "content": { "modulesContent": { // 原有的$edgeAgent、$edgeHub、OPCPublisher配置内容 } }, "targetCondition": "tags.environment='production'", "priority": 10 }各字段说明:
id:配置ID,必须和URL中的configid保持一致targetCondition:指定配置应用的设备筛选条件(可基于设备标签、类型等,例如deviceId='myEdgeDevice'或tags.group='edge-devices')priority:配置优先级,数值越高优先级越高,用于多个配置冲突时的决议
修正代码中的文件名错误
原代码中读取的文件名deloyment.manifest.json存在拼写错误,改为正确的deployment.manifest.json,避免文件读取失败。可选:代码中动态构建请求体
若不想修改原JSON文件,可在代码中动态封装请求体:private static string DeployConfiguration(string iotHubName, string token) { using var client = new HttpClient(); client.DefaultRequestHeaders.Add("Authorization", token); // 读取原模块配置 var originalModuleContent = File.ReadAllText("deployment.manifest.json"); var moduleContentObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(originalModuleContent); // 构建完整配置请求体 var configRequestBody = new Newtonsoft.Json.Linq.JObject { ["id"] = "configid", ["content"] = moduleContentObj, ["targetCondition"] = "tags.environment='production'", ["priority"] = 10 }; var stringContent = new StringContent(configRequestBody.ToString(), Encoding.UTF8, "application/json"); var restUriPut = $"https://{iotHubName}/configurations/configid?api-version=2021-04-12"; using var resultPut = client.PutAsync(restUriPut, stringContent).Result; return resultPut.StatusCode.ToString(); }验证API版本
建议使用稳定版API,比如2021-04-12,替代预览版2020-05-31-preview,提升兼容性。
内容的提问来源于stack exchange,提问作者Victor Pieper
相关产品推荐
相关产品推荐

