使用持续部署发布机器人后不显示图像
Images are not displayed after publishing the bot with continuous deployment
我使用 Bot Framework 开发了一个机器人。当我在 Bot Framework Emulator 上本地 运行 它时,它会显示图像。但是在通过创建私有 GitHub 存储库将其发布到 Azure 后,会显示 none 个图像。我正在使用 Direct-Line API 3.0。可能是什么原因?
就像,这是我的项目的树视图。图像文件夹位于内容根目录中。
我正在使用以下静态方法来检索图像路径。
public static string CreateImagePath(string filename)
{
return Path.Combine(TempData.HostingEnvironment?.ContentRootPath, "images", $"{filename}");
}
然后将其转换为Uri,并将其分配给Adaptive Card的图像。这是代码片段。
(AdaptiveCardFactory.CreateAdaptiveElement(card, "image") as AdaptiveImage).Url =
new Uri(PathFactory.CreateImagePath("welcome_card_image.png"));
CreateAdaptiveElement 定义为:
public static AdaptiveElement CreateAdaptiveElement(AdaptiveCard card, string adaptiveElementId)
{
return card.Body.Find(ae => ae.Id == adaptiveElementId);
}
这是我在本地 运行 机器人时返回的 Uri。它工作正常。
file:///C:/Users/Husai/source/repos/PanjaSahibBot/images/welcome_card_image.png
这是发布后返回的内容。
file:///D:/home/site/wwwroot/images/welcome_card_image.png
而且,它不起作用。
这是最新的命令日志。
Command: "D:\home\site\deployments\tools\deploy.cmd"
Handling ASP.NET Core Web Application deployment.
Restoring packages for D:\home\site\repository\GurdwaraBot.csproj...
Generating MSBuild file D:\home\site\repository\obj\GurdwaraBot.csproj.nuget.g.props.
Generating MSBuild file D:\home\site\repository\obj\GurdwaraBot.csproj.nuget.g.targets.
Restore completed in 5.02 sec for D:\home\site\repository\GurdwaraBot.csproj.
Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 1.41 sec for D:\home\site\repository\GurdwaraBot.csproj.
GurdwaraBot -> D:\home\site\repository\bin\Release\netcoreapp2.2\GurdwaraBot.dll
GurdwaraBot -> D:\local\Tempd6da8df6d390f3\
Creating app_offline.htm
KuduSync.NET from: 'D:\local\Tempd6da8df6d390f3' to: 'D:\home\site\wwwroot'
Copying file: 'GurdwaraBot.deps.json'
Copying file: 'GurdwaraBot.dll'
Copying file: 'GurdwaraBot.pdb'
Copying file: 'GurdwaraBot.runtimeconfig.json'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images\bill.png'
Copying file: 'images\feedback.png'
Copying file: 'images\Festivals.jpg'
Copying file: 'images\festivals_bandi_chhor_divas.jpg'
Copying file: 'images\festivals_gurpurab.jpeg'
Copying file: 'images\festivals_hola_mohalla.jpg'
Copying file: 'images\festivals_maghi.jpg'
Copying file: 'images\festivals_martyrdom_of_guru_arjan.jpg'
Copying file: 'images\festivals_parkash_utsav_dasveh_patshah.jpg'
Copying file: 'images\festivals_vaisakhi.jpg'
Copying file: 'images\menu_card_image.png'
Copying file: 'images\panja_thumbnail_1.png'
Copying file: 'images\panja_thumbnail_2.png'
Copying file: 'images\panja_thumbnail_3.png'
Copying file: 'images\pof_guest_hotel.jpg'
Copying file: 'images\question.png'
Omitting next output lines...
Finished successfully.
这就是我所期待的。
Locally executed
而且,这就是我通过 DirectLine 得到的!!
Actual result
这是我的 welcome_card.json
的内容
{
"type": "AdaptiveCard",
"body": [
{
"type": "Image",
"id": "image",
"horizontalAlignment": "Center",
"style": "Person",
"url": "",
"size": "Medium"
},
{
"type": "TextBlock",
"horizontalAlignment": "Center",
"size": "Medium",
"weight": "Bolder",
"color": "Accent",
"text": "Welcome to Gurdwara Bot",
"wrap": true
},
{
"type": "TextBlock",
"horizontalAlignment": "Left",
"text": "Hi there! I'm the Sri Panja Sahib's support bot. What can I help you with today? Just so you know, you can enter **MENU** anytime you want to go back to the options below, or just go ahead type your query.",
"wrap": true
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Get an Overview",
"data": {
"dataId": "overview"
}
},
{
"type": "Action.Submit",
"title": "Ask a Question",
"data": {
"dataId": "question"
}
},
{
"type": "Action.Submit",
"title": "Book a Room",
"data": {
"dataId": "room"
}
},
{
"type": "Action.Submit",
"title": "Give a Feedback",
"data": {
"dataId": "feedback"
}
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0",
"speak": "Hi there! I'm the Sri Panja Sahib's support bot. What can I help you with today? Just so you know, you can enter **MENU** anytime you want to go back to the options below, or just go ahead type your query."
}
我已经定义了 AdaptiveCardFactory 来处理卡片。
public class AdaptiveCardFactory
{
public static AdaptiveCard CreateAdaptiveCard(string path)
{
try
{
var adaptiveCardJson = File.ReadAllText(path);
AdaptiveCardParseResult result = AdaptiveCard.FromJson(adaptiveCardJson);
return result.Card;
}
catch (AdaptiveSerializationException)
{
throw;
}
}
public static Attachment CreateAdaptiveCardAttachment(AdaptiveCard card)
{
return new Attachment
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = card,
};
}
public static AdaptiveElement CreateAdaptiveElement(AdaptiveCard card, string adaptiveElementId)
{
return card.Body.Find(ae => ae.Id == adaptiveElementId);
}
}
TL;DR;
您必须为 AdaptiveCards 中显示的项目提供 public URLs,而不是本地项目。它在本地与模拟器一起工作,因为......你在本地,并且模拟器可以访问你的本地文件,因此它可以理解具有本地位置的文件(C:\...
或 D:\...
文件)。
所以改变你的路径,让它使用你的sub-domain:你可以在这里做,例如使用配置变量而不是TempData.HostingEnvironment?.ContentRootPath
public static string CreateImagePath(string filename)
{
return Path.Combine(TempData.HostingEnvironment?.ContentRootPath, "images", $"{filename}");
}
详情:
AdaptiveCard
item 在 bot 消息中作为附件传递,里面的所有内容都由客户端(通道)呈现,因此它只能从外部呈现 "visible" 的内容.
在此处查看我的演示:我使用了一张包含 2 张图片的 ImageSet 的卡片:一张在网络上带有 URL,另一张带有与您的一样的 URL 构建。
本地:两张图都OK。
已发布:仅显示第一张图片
如果您查看 right-side 上的 Inspector,很明显您必须更改构建映像的方式 Url。
您还可以通过 right-clicking 图像所在的区域查看您部署的网络聊天,您会发现 link 带有 D:\...
路径
代码修复
1,将您的 images
文件夹移动到项目的 wwwroot
文件夹中。然后您可以执行以下操作:
public string CreateImagePath(string filename)
{
if (_hostingEnvironment.IsDevelopment())
{
return Path.Combine(TempData.HostingEnvironment?.ContentRootPath, "wwwroot", "images", $"{filename}");
}
else
{
var targetUri = new Uri(new Uri($"https://{Environment.ExpandEnvironmentVariables("%WEBSITE_SITE_NAME%")}.azurewebsites.net"), Path.Combine("images", $"{filename}"));
return targetUri.ToString();
}
}
我使用 Bot Framework 开发了一个机器人。当我在 Bot Framework Emulator 上本地 运行 它时,它会显示图像。但是在通过创建私有 GitHub 存储库将其发布到 Azure 后,会显示 none 个图像。我正在使用 Direct-Line API 3.0。可能是什么原因?
就像,这是我的项目的树视图。图像文件夹位于内容根目录中。
我正在使用以下静态方法来检索图像路径。
public static string CreateImagePath(string filename)
{
return Path.Combine(TempData.HostingEnvironment?.ContentRootPath, "images", $"{filename}");
}
然后将其转换为Uri,并将其分配给Adaptive Card的图像。这是代码片段。
(AdaptiveCardFactory.CreateAdaptiveElement(card, "image") as AdaptiveImage).Url =
new Uri(PathFactory.CreateImagePath("welcome_card_image.png"));
CreateAdaptiveElement 定义为:
public static AdaptiveElement CreateAdaptiveElement(AdaptiveCard card, string adaptiveElementId)
{
return card.Body.Find(ae => ae.Id == adaptiveElementId);
}
这是我在本地 运行 机器人时返回的 Uri。它工作正常。
file:///C:/Users/Husai/source/repos/PanjaSahibBot/images/welcome_card_image.png
这是发布后返回的内容。
file:///D:/home/site/wwwroot/images/welcome_card_image.png
而且,它不起作用。
这是最新的命令日志。
Command: "D:\home\site\deployments\tools\deploy.cmd"
Handling ASP.NET Core Web Application deployment.
Restoring packages for D:\home\site\repository\GurdwaraBot.csproj...
Generating MSBuild file D:\home\site\repository\obj\GurdwaraBot.csproj.nuget.g.props.
Generating MSBuild file D:\home\site\repository\obj\GurdwaraBot.csproj.nuget.g.targets.
Restore completed in 5.02 sec for D:\home\site\repository\GurdwaraBot.csproj.
Microsoft (R) Build Engine version 15.9.20+g88f5fadfbe for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 1.41 sec for D:\home\site\repository\GurdwaraBot.csproj.
GurdwaraBot -> D:\home\site\repository\bin\Release\netcoreapp2.2\GurdwaraBot.dll
GurdwaraBot -> D:\local\Tempd6da8df6d390f3\
Creating app_offline.htm
KuduSync.NET from: 'D:\local\Tempd6da8df6d390f3' to: 'D:\home\site\wwwroot'
Copying file: 'GurdwaraBot.deps.json'
Copying file: 'GurdwaraBot.dll'
Copying file: 'GurdwaraBot.pdb'
Copying file: 'GurdwaraBot.runtimeconfig.json'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'imagesd.png'
Copying file: 'imagesn.png'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images.jpg'
Copying file: 'images\bill.png'
Copying file: 'images\feedback.png'
Copying file: 'images\Festivals.jpg'
Copying file: 'images\festivals_bandi_chhor_divas.jpg'
Copying file: 'images\festivals_gurpurab.jpeg'
Copying file: 'images\festivals_hola_mohalla.jpg'
Copying file: 'images\festivals_maghi.jpg'
Copying file: 'images\festivals_martyrdom_of_guru_arjan.jpg'
Copying file: 'images\festivals_parkash_utsav_dasveh_patshah.jpg'
Copying file: 'images\festivals_vaisakhi.jpg'
Copying file: 'images\menu_card_image.png'
Copying file: 'images\panja_thumbnail_1.png'
Copying file: 'images\panja_thumbnail_2.png'
Copying file: 'images\panja_thumbnail_3.png'
Copying file: 'images\pof_guest_hotel.jpg'
Copying file: 'images\question.png'
Omitting next output lines...
Finished successfully.
这就是我所期待的。 Locally executed 而且,这就是我通过 DirectLine 得到的!! Actual result
这是我的 welcome_card.json
的内容 {
"type": "AdaptiveCard",
"body": [
{
"type": "Image",
"id": "image",
"horizontalAlignment": "Center",
"style": "Person",
"url": "",
"size": "Medium"
},
{
"type": "TextBlock",
"horizontalAlignment": "Center",
"size": "Medium",
"weight": "Bolder",
"color": "Accent",
"text": "Welcome to Gurdwara Bot",
"wrap": true
},
{
"type": "TextBlock",
"horizontalAlignment": "Left",
"text": "Hi there! I'm the Sri Panja Sahib's support bot. What can I help you with today? Just so you know, you can enter **MENU** anytime you want to go back to the options below, or just go ahead type your query.",
"wrap": true
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Get an Overview",
"data": {
"dataId": "overview"
}
},
{
"type": "Action.Submit",
"title": "Ask a Question",
"data": {
"dataId": "question"
}
},
{
"type": "Action.Submit",
"title": "Book a Room",
"data": {
"dataId": "room"
}
},
{
"type": "Action.Submit",
"title": "Give a Feedback",
"data": {
"dataId": "feedback"
}
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0",
"speak": "Hi there! I'm the Sri Panja Sahib's support bot. What can I help you with today? Just so you know, you can enter **MENU** anytime you want to go back to the options below, or just go ahead type your query."
}
我已经定义了 AdaptiveCardFactory 来处理卡片。
public class AdaptiveCardFactory
{
public static AdaptiveCard CreateAdaptiveCard(string path)
{
try
{
var adaptiveCardJson = File.ReadAllText(path);
AdaptiveCardParseResult result = AdaptiveCard.FromJson(adaptiveCardJson);
return result.Card;
}
catch (AdaptiveSerializationException)
{
throw;
}
}
public static Attachment CreateAdaptiveCardAttachment(AdaptiveCard card)
{
return new Attachment
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = card,
};
}
public static AdaptiveElement CreateAdaptiveElement(AdaptiveCard card, string adaptiveElementId)
{
return card.Body.Find(ae => ae.Id == adaptiveElementId);
}
}
TL;DR;
您必须为 AdaptiveCards 中显示的项目提供 public URLs,而不是本地项目。它在本地与模拟器一起工作,因为......你在本地,并且模拟器可以访问你的本地文件,因此它可以理解具有本地位置的文件(C:\...
或 D:\...
文件)。
所以改变你的路径,让它使用你的sub-domain:你可以在这里做,例如使用配置变量而不是TempData.HostingEnvironment?.ContentRootPath
public static string CreateImagePath(string filename)
{
return Path.Combine(TempData.HostingEnvironment?.ContentRootPath, "images", $"{filename}");
}
详情:
AdaptiveCard
item 在 bot 消息中作为附件传递,里面的所有内容都由客户端(通道)呈现,因此它只能从外部呈现 "visible" 的内容.
在此处查看我的演示:我使用了一张包含 2 张图片的 ImageSet 的卡片:一张在网络上带有 URL,另一张带有与您的一样的 URL 构建。
本地:两张图都OK。
已发布:仅显示第一张图片
如果您查看 right-side 上的 Inspector,很明显您必须更改构建映像的方式 Url。
您还可以通过 right-clicking 图像所在的区域查看您部署的网络聊天,您会发现 link 带有 D:\...
路径
代码修复
1,将您的 images
文件夹移动到项目的 wwwroot
文件夹中。然后您可以执行以下操作:
public string CreateImagePath(string filename)
{
if (_hostingEnvironment.IsDevelopment())
{
return Path.Combine(TempData.HostingEnvironment?.ContentRootPath, "wwwroot", "images", $"{filename}");
}
else
{
var targetUri = new Uri(new Uri($"https://{Environment.ExpandEnvironmentVariables("%WEBSITE_SITE_NAME%")}.azurewebsites.net"), Path.Combine("images", $"{filename}"));
return targetUri.ToString();
}
}