1

I am building a HeroCard containing a CardImage which must show an image. Up until now I was using

HeroCard hcBody = new HeroCard
{
    Text = "IMG",
    Images = new List<CardImage> { 
       new CardImage(url: $"https://www.example.com/Pictures/" + picNo + ".jpg") },
    Buttons = new List<CardAction> { 
       new CardAction(ActionTypes.ImBack, "SELECT"+picNo , value: picvalue) },
 };
 msg.Attachments.Add(hcBody.ToAttachment());

This is the HeroCard with a text,the image loaded from a URL adding the image number dynamically and at the end its type. Then I am adding a button with an action,text and value

Now the issue is that I need to load the images from the project's path. I tried to achieve it by

var picPath=System.Configuration.ConfigurationManager.AppSettings["picServerPath"];

and modifying the CardImage url to

Images = new List<CardImage> { new CardImage(url: picPath+ picNo + ".jpg") }

Using a logger I saw that the built path is correct, the HeroCard shows up but the images are missing. So I guess the URL of the CardImage needs to be created in a different way if I want to use the project's path on the server?

J-K
  • 139
  • 11
  • There's a lot of confusion here. It sounds like you want to continue loading the image from a public URL but you want the new URL to point to the same domain where your app is deployed. For some reason you've put the new URL in your app settings, but you could have just as easily done that with the old URL so this whole configuration-loading thing is just a red herring, right? You say the "built path" is correct, but what path is that? Have you tried entering the path into a browser to see if that URL does indeed return an image? – Kyle Delaney Oct 09 '19 at 17:24
  • It looks like you accepted the answer when you asked this question a year and a half ago: https://stackoverflow.com/questions/49347786/hero-card-image-attachment-not-loading – Kyle Delaney Oct 09 '19 at 17:46
  • @KyleDelaney I must change the https://www.example.com/Pictures/ to ~/Pictures/ .The URl will change so I can't use it anymore in my code.I need to add the logic of finding the picture through the root folder. Also I tried the answer of the question I did in the past with no luck this time. Have in mind that bot framework is updated. I do not know if anything changed regarding the build of a card image. – J-K Oct 10 '19 at 05:02
  • I see that you got a good answer below as well but it sounds like you're still having difficulties. Would you prefer to embed the image in the card rather than linking to it? – Kyle Delaney Oct 10 '19 at 18:10

1 Answers1

1

You need to make sure that every URL you use when creating a CardImage is a valid absolute HTTPS URL (otherwise it wont work in Facebook for example). Remember that these URLs will be rendered in the client device so they must be accessible from anywhere.

First, if you want to host the images in your bot webapp, make sure they are in the wwwroot folder.

Second, I'd recommend having a setting in appsettings.json with the base url where your images will be hosted (for example https://www.example.com/Pictures/).
For now it can be your bot webapp domain and later it can be a blob storage, or whatever.
Then make a simple class with a method that receives the image name and prefixes it with this setting so you don't need to repeat the same code in every dialog. Example:

appsettings.json

{
  "ImagesBaseUrl": "https://www.example.com/Pictures/",
  "..."
}

Service

public interface IImageService
{
    string GetImagePath(string imageName);
}

public class ImageService : IImageService
{
    private readonly string _baseUrl;

    public ImageService(IConfiguration configuration)
    {
        _baseUrl = configuration?.GetValue<string>("ImagesBaseUrl") ?? throw new ArgumentNullException(nameof(configuration));
    }

    // probably improve this further with / checking, handle extensions, etc
    public string GetImagePath(string imageName)
    {
        return string.Concat(_baseUrl, imageName);
    }
}

Then inject IImageService in your bot/dialog or wherever you need to build hero cards.

Edit: If you really want to get the server absolute path your app is running on, you'll have to use something like Server.MapPath

However if you're using BotFramework V4 you're probably using NET Core so you'll have to use one of these depending on your NET Core version. You'd better injecting IHostingEnvironment/IWebHostEnvironment in a single place like the service I mentioned above. Just imagine they change it again in the future and you'd have to rename in lots of dialogs.

I'd still prefer to use the appsettings version since its more versatile in case you want to change it in the future (you don't have to change code and rebuild the app).

André Mantas
  • 482
  • 4
  • 13
  • I have done it with a valid HTTPS URL and it works fine but I can't keep this logic. The software will be moved to another domain so I need a path that will not need any future modifications. That is why I am trying to achieve something like ~/Pictures/ so that I will use the root path which will be always the same – J-K Oct 10 '19 at 05:08
  • That's why I suggested putting it in appsettings. You can change it in runtime without rebuilding the code. Something like ~/Pictures/ won't work by itself, this path will be fetched in the domain the client is talking with the bot, not in the bot server. It can be Facebook, Skype, or a web chat using direct line in another domain. You need an absolute URL in the activity attachment before it is sent to the conversation. I'll update my answer on how to get absolute path programmatically. – André Mantas Oct 10 '19 at 06:55